




已阅读5页,还剩180页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章汇编语言程序设计 1 机器语言 MachineLanguage 机器语言是一种用二进制表示指令和数据 能被机器直接识别的计算机语言 它的缺点是不直观 不易理解和记忆 因此编写 阅读和修改机器语言程序都比较繁琐 但机器语言程序是计算机惟一能够直接理解和执行的程序 具有执行速度快 占用内存少等特点 2 高级语言 HighLevelLanguage 如果说机器语言是面向机器的 那么高级语言 如BASIC FORTRAN等 则是 面向过程 的语言 利用这些语言编程 程序员可以完全不考虑机器的结构特点 不必了解和熟记机器的指令系统 仅使用一些接近人们书写习惯的英语和数学表达式形式的语句去编制程序 这样编写的程序与问题本身的数学模型之间有着良好的对应关系 可在各种机器上通用 不同机器之间仅做少量修改 但是 这种用高级语言编写的源程序并不能在机器上直接执行 需要被翻译成对应的目标程序 即机器语言程序 机器才能运行 把具有这种翻译作用的程序称为解释程序或编译程序 见图5 1 图5 1编译程序的功能示意图 由于高级语言程序是在未考虑机器的结构特点的条件下编写的 因而它就不能充分利用某种具体CPU所具有的某些特性 而通过编译或解释程序生成的目标程序往往比较冗长 占有较多的内存空间 执行时间也比较长 这就限制了它在某些场合下的运用 例如 实时的数据采集 检测和在线的实时控制等 往往要求程序的目标代码尽可能少占内存并有尽可能快的执行速度 在这些场合下 使用高级语言编写的程序常常不能满足要求 3 汇编语言 AssemblyLanguage 汇编语言是一种采用助记符表示的程序设计语言 即用助记符来表示指令的操作码和操作数 用标号或符号代表地址 常量或变量 助记符一般都是英文字的缩写 以方便人们书写 阅读和检查 实际上 用汇编语言编写的汇编语言源程序就是机器语言程序的符号表示 汇编语言源程序与其经过汇编所产生的目标代码程序之间有明显的一一对应关系 故也称汇编语言为符号语言 用汇编语言编写程序能够直接利用硬件系统的特性 如寄存器 标志 中断系统等 直接对位 字节 字寄存器或存储单元 I O端口进行处理 同时也能直接使用CPU指令系统和指令系统提供的各种寻址方式 编制出高质量的程序 这样的程序不但占用内存空间少 而且执行速度快 当然 由于源程序和所要解决的问题的数学模型之间的关系不够直观 使得汇编语言程序设计需要较多的软件开发时间 也增加了程序设计过程中出错的可能性 用汇编语言编写的源程序也需要翻译成目标程序才能被机器执行 这个翻译过程称为汇编 完成汇编任务的程序称为汇编程序 见图5 2 图5 2汇编程序的功能示意图 汇编程序是最早也是最成熟的一种系统软件 它除了能够将汇编语言源程序翻译成机器语言程序这一主要功能外 还能够根据用户的要求自动分配存储区域 包括程序区 数据区 暂存区等 自动地把各种进位制数转换成二进制数 把字符转换成ASCII码 计算表达式的值等 自动对源程序进行检查 给出错误信息 如非法格式 未定义的助记符 标号 漏掉操作数等 等 具有这些功能的汇编程序又称为基本汇编 或小汇编ASM 在基本汇编的基础上 进一步允许在源程序中把一个指令序列定义为一条宏指令的汇编程序 就叫做宏汇编 MASM 它包含全部ASM功能 还增加了宏指令 结构 记录等高级汇编语言功能 本章讲述 4 1汇编语言的格式4 2语句行的构成4 3指示性语句4 4指令语句4 5汇编语言程式设计及举例 4 1汇编语言的格式4 1 18086汇编语言程序的一个例子 MY DATASEGMENT 定义数据段SUMDB 为符号SUM保留一个字节MY DATAENDS 定义数据段结束MY CODESEGMENT 定义码段ASSUMECS MY CODE 规定CS和DS的内容DS MY DATAPORT VALEQU3 端口的符号名GO MOVAX MY DATA DS初始化为MY DATAMOVDS AXMOVSUM 0 清SUM单元CYCLE CMPSUM 100 SUM单元与100相比较JNANOT DONE 若未超过 转至NOT DONEMOVAL SUM 若超过 把SUM单元的内容OUTPORT VAL AL 通过AL输出HLT 然后停机NOTDONE INAL PORT VAL 未超过时 输入下一个字节ADDSUM AL 与以前的结果累加JMPCYCLE 转至CYCLEMYCODEENDS 码段结束ENDGO 整个程序结束 分段结构由上面的例子可以看出 汇编语言源程序的结构是分段结构形式 一个汇编语言源程序由若干段 SEGMENT 组成 每个段以SEGMENT语句开始 以ENDS语句结束 整个源程序的结尾是END语句 这里所说的汇编语言源程序中的段与前面讨论的CPU管理的存储器的段 既有联系 又在概念上有所区别 我们已经知道 微处理器对存储器的管理是分段的 因此 在汇编语言程序中也要求分段组织指令 数据和堆栈 以便将源程序汇编成为目标程序后 可以分别装入存储器的相应段中 但是 以8086 8088CPU为例 它有四个段寄存器 CS ES SS和DS 因此CPU对存储器按照四个物理段进行管理 即数据段 附加段 堆栈段和代码段 任何时侯CPU只能访问四个物理段 而在汇编语言源程序中 设置段的自由度比较大 例如 一个源程序中可以有多个数据段或多个代码段等等 一般来说 汇编语言源程序中段的数目可以根据实际需要而设定 为了和CPU管理的存储器物理段相区别 我们将汇编语言程序中的段称为逻辑段 在不致发生混淆的地方 有时简称为段 在上面的简单源程序中只有两个逻辑段 一个逻辑段的名字是DATA 其中存放着与程序有关的数据 称为逻辑数据段 另一个逻辑段的名字是CODE 其中包含着程序的指令 称为逻辑代码段 每个段内均有若干行语句 STATEMENT 因此 可以说一个汇编源程序是由一行一行的语句组成的 下面我们来讨论汇编语言语句的类型和组成 4 1 28086汇编语言源程序的格式 8086的汇编语言的源程序是分段的 由若干个段形成一个源程序 源程序的一般格式为 NAME1SEGMENT语句 语句NAME1ENDSNAME2SEGMENT语句 语句NAME2ENDS END 标号 每一个段有一个名称 以符号SEGMENT作为段的开始 以语句ENDS作为段的结束 这两者都必须有名称 而且名称必须相同 由若干个段组成一个源程序 整个源程序以语句END作为结束 总之 8086的源程序是由若干段组成的 而一个段又是由若干个语句行组成的 所以 语句行是汇编语言源程序的基础 4 2语句行的构成 语句行是由标记 Token 及分隔符按照一定的规则组织起来的 标记是IBM宏汇编源程序的最小的 有意义的单位 汇编语言语句的类型和格式1 语句的类型汇编语言源程序中的语句可以分为两种类型 指令语句和伪指令语句 1 指令语句 它是能产生目标代码 CPU可以执行的能完成特定功能的语句 2 伪指令语句 它是一种不产生目标代码的语句 它仅仅在汇编过程中告诉汇编程序应如何汇编 例如 告诉汇编程序已写出的汇编语言源程序有几个段 段的名字是什么 定义变量 定义过程 给变量分配存储单元 给数字或表达式命名等 显然 伪指令语句是汇编程序在汇编时使用的 由上例看出8086汇编的一个语句行由以下4个部分组成 标号 或名称 操作码操作数 注释各部分之间至少要用一个空格作为间隔 IBM宏汇编对于语句行的格式是自由的 但如果写成格式化就便于阅读 建议读者按格式化来写语句行 另外 IBM宏汇编并不要求一个语句只能写一行 一个语句可以有后续行 规定以字符 作为后续行的标志 4 2 1标记 IBM宏汇编的字符集IBM宏汇编中所使用的字符集仅是ASCII和EBCDIC 扩展的BCD码 字符集的一个子集 它由以下几部分组成 1 字母包含大写的英文字母 ABCD XYZ 小写的英文字母 abc xyz 2 数字阿拉伯数字 0123456789 3 特殊字符可打印字符如图4 1中所示 非打印字符有 空格 制表符 TAB键 回车和换行 若在源程序中包含任何不属于上列字符集中的字符 则汇编程序就把它们作为空格处理 虽然字符 是字符集中的一个字符 但紧跟在回车换行之后的符号 是代表一个连续行 所以 汇编程序也把它当做空格处理 2 界符 Delimiters 界符是一些特殊字符 利用它们可以表明某个标记的结束 它们本身也有一定的意义 这一点就与分隔符 空格 不同 例子中的冒号 逗号 都是一种界符 IBM宏汇编中的界符集如图4 2所示 IBM宏汇编中的界符集语句中有了界符就可以不再用分隔符 但为了程序更清晰可读 有时仍用分隔符 3 常量 Constants 凡是出现在8086源程序中的固定值 它在程序运行期间不会变化 就称为常量 例子中的数0 3 100等都是常量 而且是数字常量 IBM宏汇编中允许的常量为 1 数字 整数 常量 二进制常量以字母B结尾的由一串 0 和 1 组成的序列 例如 00101100B 十进制常量由若干个0 9的数字组成的序列 可以以字母D作结尾 或没有任何字母作结尾 例如 1234D或1234 八进制常量以字母Q 或字母O 结尾 由若干个0 7的数字组成的序列 例如255Q 377Q等 十六进制常量以字母H结尾 由若干个0 9的数字或A F的字母所组成的序列 为了避免与标识符相混淆 十六进制数在语句中必须以数字打头 所以 凡是以字母A F开始的十六进制数 必须在前面加上数字0 例如56H 0BA3FH等 2 字符串常量字符串常量是由包含在单引号内的1至2个ASCII字符构成的 汇编程序把它们表示成一个字节序列 一个字节对应一个字符 把引号中的字符翻译成它的ASCII码值 例如字符 A 等价于41H 字符 AB 等价于4142H 在可以使用单字节立即数的地方 就可以使用单个字符组成的字符串常量 在可以使用字立即数的地方 就可以使用两个字符组成的字符串常量 只有在初始化存储器时才可以使用多于两个字符的字符串常量 4 标识符 Identifiers 标识符是由程序员自由建立起来的 有特定意义的字符序列 如例子中的SUM CYCLE和PORT VAL等等 一个标识符是由最多为31个字母 数字及规定的特殊字符 等组成的 而且不能用数字打头 以免与十六进制数相混淆 5 保留字 Reservedwords 保留字看上去像标识符 但是它们在语言中有特殊的意义 而且不能用它们作为标识符 如例子中的SEGMENT MOV EQU AL等都是保留字 实际上凡是8086的指令助记符 汇编语言中的命令 伪指令 寄存器名等都是保留字 6 注释 Comment 为了使汇编语言的源程序更便于阅读和理解 常在源程序中加上注释 注释是在分号 后面的任意的字符序列 直到行的结尾 在汇编时 汇编程序对它们并不进行处理 在可打印的文件中 注释和源程序一起打印 4 2 2符号 在汇编语言源程序中 为了使程序更具有普遍性 也便于程序的修改 用户常用符号等代替存储单元 数据 表达式等等 如例中的存储单元SUM 输入输出端口PROT VAL等就是 符号 Symbol 是一种标识符 它要符合标识符的组成规则 在实际使用中的符号可以分成五类 即寄存器 变量 标号 数 其他 每个符号都具有一定的属性 以允许汇编程序使用它来代表所需的信息 1 寄存器 Registers 8086的寄存器常在操作数场出现 代表某一个操作数 每个寄存器都有一种类型特性 由这些类型可以确定它是一个字节寄存器还是一个字寄存器 8086的标志位被看作是一位寄存器 2 变量 Variable 存放在存储单元中的操作数是变量 因为它们的值是可以改变的 在程序中出现的是存储单元地址的符号 即它们的名称 所有的变量都具有三种属性 1 段值 SEGMENT 即变量单元所在段的段地址 段的起始地址 的高16位 低4位始终为0 2 偏移量 OFFSET 即变量单元地址与段的起始地址之间的偏移量 16位 3 类型 TYPE 变量有三种类型 字节 BYTE 字 WORD 和双字 DOUBLEWORD 变量通常是用存储器初始化命令定义的 3 标号 Label 标号是某条指令所存放单元的符号地址 它是转移 条件转移或无条件转移 指令或调用 CALL 指令的目标操作数 对于汇编程序来说 标号与变量是类似的 都是存储单元的符号地址 只是标号对应的存储单元中存放的是指令 而变量所对应的存储单元中存放的是数据 所以 标号也有三种属性 1 段值 2 偏移量 3 类型 标号的类型与变量不同 它的类型是NEAR或是FAR NEAR是指转移到此标号所指的语句 或调用此子程序或过程 只需要改变IP值 而不改变CS值 也即转移指令或调用指令与此标号所指的语句或过程在同一段内 FAR与NEAR不同 要转移到标号所指的语句 或调用此子程序或过程 不仅需要改变IP的值 而且需要改变CS 即是段交叉转移或调用 若没有对标号进行类型说明 就假定它为NEAR 4 数在汇编语言源程序中的常数也常以符号的形式出现 这样就更具有通用性 更便于修改 如上例中的就是把端口地址3定义为一个符号PORT VAL 5 其他符号除了上述4种符号以外 在汇编语言中还经常出现一些其他符号 把它们用作汇编程序中的伪指令名字 4 2 3表达式 表达式 Expressions 是由上面讨论过的标记 Token 符号 Symbol 通过运算符组合起来的 粗略地说 一个表达式是一个由操作数和运算符组合的序列 在汇编时它能产生一个值 1 操作数 Operands 一个操作数可以是一个寄存器名 一个常量 数字常量或字符串常量 或一个存储器操作数 1 常量操作数具有数字值的操作数是常量或是表示常量的标识符 符号 2 存储器操作数存储器操作数 通常是标识符 可以分成标号 Label 和变量 Variable 两种 标号是可执行的指令语句的符号地址 通常是作为转移指令JMP和调用指令CALL的目标操作数 变量通常是指存放在一些存储单元中的值 这些值在程序运行过程中是可变的 变量可以具有以下几种寻址方式 直接寻址16位地址偏移量包含在指令中 基址寻址由一个基址寄存器 BX或BP 的内容 加上一个在指令中指定的8位或16位位移量 决定变量的地址 变址寻址由一个变址寄存器 SI或DI 的内容 加上一个在指令中指定的8位或16位位移量 决定变量的地址 基址变址寻址由一个基址寄存器 BX或BP 的内容 加上一个变址寄存器 SI或DI 的内容 再加上一个在指令中指定的8位或16位位移量 决定变量的地址 作为存储器操作数的标号和变量都有三种属性 段值 段内地址偏移量 类型 一个运算符取一个或多个操作数的值 以形成一个新值 在IBM宏汇编中有五种运算符 2 运算符 Operators IBM宏汇编通常有以下几种运算符 算术运算符 ArithmeticOperators 逻辑运算符 LogicalOperators 关系运算符 RelationalOperators 分析运算符 AnalyticOperators 合成运算符 SyntheticOperators 1 算术运算符这是读者十分熟悉的运算符 加 减 乘 除 运算符 另一个算术运算符是MOD 求余 它产生除法以后的余数 因此19 7是2 商是2 而19MOD7是5 余数是5 算术运算符应用于数字操作数 结果也是数字的 当算术运算符应用于存储器即地址操作数时其规则就更加严格 只有当结果有明确的 有意义的物理解释时 这些运算才是有效的 2 逻辑运算符按位操作的逻辑运算符有 AND 与 OR 或 XOR 异或 和NOT 非 逻辑运算的操作数只能是数字的 而且结果是数字的 存储器地址操作数不能进行逻辑运算 注意 AND OR XOR和NOT 也是8086指令的助记符 但是 作为IBM宏汇编的运算符是在程序汇编时计算的 而作为指令的助记符 则是在程序执行时计算的 3 关系运算符在IBM宏汇编中有以下关系运算符 相等EQ Equal 不等NE NotEqual 小于LT LessThan 大于GT GreaterThan 小于或等于LE LessThanorEqual 大于或等于GE GreaterThanorEqual 关系运算的两个操作数 或者都是数字的 或者是同一个段的存储器地址 结果始终是一个数字值 若关系是假 则结果为0 若关系是真 则结果为0FFFFH 4 分析运算符分析运算符可以把存储器操作数分解为它的组成部分 如它的段值 段内偏移量和类型 5 合成运算符合成运算符可以由已经存在的存储器操作数生成一个段值与偏移量相同 而类型不同的新的存储器操作数 4 2 4语句 如前所述 一个汇编语言的源程序是由一条条语句组成的 语句 Statements 就是完成一个何种动作的说明 源程序中的语句可分成两类 指令语句 汇编程序把它们翻译成机器代码 这些代码命令8086执行某些操作 如MOV ADD JMP等 指示性语句 伪指令 汇编程序并不把它们 也不可能 翻译成机器代码 只是用来指示 引导汇编程序在汇编时进行一些操作 如定义符号 分配存储单元 初始化存储器等等 所以伪指令本身不占用存储单元 两种语句的格式是类似的 指令语句的格式为 标号 助记符参数 参数 注释指示性语句的格式为 名称命令参数 参数 注释在一个指令语句中的标号后面跟有冒号 而在一个指示性语句中的名字后面没有冒号 这就是这两种语句在格式上的主要区别 一个标号与一条指令的地址符号名相联系 标号可以作为JMP指令和CALL指令的目标操作数 指示性语句中的名字与指令的地址毫无关系 绝不能转向它 在指令语句中的标号 总是任选的 但在指示性语句中的名字 可能是强制的 任选的或禁止的 这取决于实际的命令 4 3指示性语句 在IBM宏汇编中有以下几种指示性语句 Directivestatements 1 符号定义语句 Symboldefinition 2 数据定义语句 Datadefinition 3 段定义语句 Segmentationdefinition 4 过程定义语句 Proceduredefinition 5 结束语句 Termination 4 3 1符号定义语句 等值语句EQUEQU语句给符号名定义一个值 或定义为别的符号名 甚至可定义为一条可以执行的指令等 EQU语句的格式为 NAMEEQUEXPRESSIONEQU语句在未解除前 不能重新定义 2 等号 Equalsign 语句 此语句的功能与EQU语句类似 最大特点是能对符号进行再定义 3 解除语句PURGE已经用EQU命令定义的符号 若以后不再用了就可以用PURGE语句来解除 PURGE语句的格式为 PURCE符号1 符号2 符号n注意 PURGE语句本身不能有名字 用PURGE语句解除后的符号可以重新定义 4 3 2数据定义语句 数据定义语句 为一个数据项分配存储单元 用一个符号名与这个存储单元相联系 且为这个数据提供一个任选的初始值 与数据项相联系的符号名称为变量 数据定义语句的例子如下 THINGDB 定义一个字节BIGGER THINGDW 定义一个字BIGGEST THINGDD 定义一个双字 THING是一个符号名 它与在存储器中的一个字节相联系 即它是一个字节变量 BIGGER THING也是一个符号名 它与在存储器中的一个字相联系 即它是一个字变量 BIGGEST THING也是一个符号名 它与在存储器中的一个双字相联系 即它是一个双字变量 由汇编程序产生的目标码 产生指令和放指令的地址 在目标码产生以后 指令已经存放在存储器中 可以执行了 在指令送至存储器的时候 数据项的初始值也可以送到存储器中 这意味着目标码除了包含指令和它们的地址以外 也可以包括数据项的起始值和它们的地址 这些初始值是由数据定义语句所规定的 例如 THINGDB25不仅使THING这个符号与一个字节的存储单元相联系 而且在汇编时会把25放入与THING相联系的存储单元中 所以THING是一个字节变量 它的初始值为25 同样 以下语句 BIGGERDW4142H在汇编时就会把41H与42H分别放至与BIGGER THING相联系的两个连续的字节单元中 下面的语句 BIGGESTDD12345678H在汇编时就会初始化 如图4 3所示 它定义了一个双字变量 且给了初始值 当汇编程序汇编时遇到 号 则它仍然为数据项分配相应的存储单元 DB分配一个字节 DW分配一个字 DD分配一个双字 但并不产生一个目标码来初始化这些存储单元 即 号是为了保留若干个存储单元 以便存放指令执行的中间结果 通常初始值能用一个表达式来规定 因为表达式是在汇编时计算的 同样 在存储单元中可以存放存储器地址值 存放内存单元的段内偏移量需用一个字 存放全地址 则需用两个字 一个字放段地址 另一个字放段内偏移量 在实际应用中 还经常会用到由字节 字或双字构成的表 这可由在数据定义语句的参数部分 引入若干个用逗号分隔的参数就可以建立一个表 下列语句定义了一个包含2的权的字节的表 POWERS 2DB1 2 4 8 16 可以用DUP来缩写若干相同的值 因而 DUP利用给出的一个初值 或一组初值 以及这些值应该重复的次数来初始化存储器 DB100DUP 0 100个字节全初始化为0DW100DUP 0 100个字全初始化为0DW10DUP 保留10个字可以用DB数据定义语句在内存中定义一个字符串 字符串中的每一个字符用它的ASCII码表示 为一个字节 故字符串的定义必须用DB命令 有两种定义字符串的方法 一种是字符串中的每一个字符分别定义 每一个字符之间用逗号分隔 另一种方法是在整个字符串的前后都加单引号 例如 EXAM1DB THISISANEXAMPLE IBM宏汇编对在程序中涉及的每一个存储单元与一种类型联系起来 这样能对访问存储器的指令产生正确的目标码 例如 数据定义语句 SUMDB 告诉汇编程序 SUM是字节类型的 以后当遇到如下的指令语句 INCSUM汇编程序就产生一个字节增量指令 而不是一个字增量指令 一个存储单元的类型如下 1 数据字节 如SUMDB 定义一个字节 2 数据字 两个连续的字节 如BIGGERDW 定义一个字 3 数据双字 四个连续的字节 如BIGGESTDD 定义一个双字 4 NEAR指令单元 如CYCLE CMPSUM 100 5 FAR指令单元 一个指令单元能出现在一条JMP或CALL语句中 若这个指令单元的类型是NEAR 汇编程序将产生一个段内JMP或CALL指令 若指令单元的类型是FAR 则产生一个段交叉JMP或CALL指令 一个NEAR指令单元规定了一个长度为两个字节的指针 即此指令单元在段内的地址偏移量 获得了此地址偏移量 就可以采用段内的转移或调用 一个FAR指令单元 规定了一个长度为四个字节的指针 即此指令单元所在段的段地址和段内的地址偏移量 只有获取了这四个字节 才能得到一个FAR指令单元的全地址 实现交叉的段调用或转移 一个存储单元地址加或减一个数字值而形成的新的存储单元与初始的存储单元有着相同的类型 例如 SUM 2是字节型 BIGGER 3是字型 而CYCLE 1是一个NEAR型指令单元 分析运算符把存储器地址操作数分解为它们的各个组成部分 这些运算符是 1 SEG 2 OFFSET 3 TYPE 4 SIZE 5 LENGTH 若在一个程序中 对它的数据段有如下定义DATA TABLESEGMENTBUFFER1DB100DUP 0 BUFFER2DW200DUP 20H BUFFER3DD100DUP 13 DATA TABLESENDS其中的每一个存储单元都有一些属性 或组成部分 分析运算符SEG 返回的是一个存储单元的段地址 即它所在段的起始地址 OFFSET运算符返回的是每一个存储单元地址的段内偏移量 即它与段地址之间的偏差 故语句 SEGBUFFER1SEGBUFFER2是相同的 它们返回的地址都是DATA TABLES的地址 所以 若要对数据段寄存器初始化 则可以采用指令 MOVAX SEGBUFFER1MOVDS AX 而OFFSET是各不相同的 若要向这些缓冲区填入新的数据 可以用一些地址指针 则可以用以下指令来初始化地址指针 MOVBX OFFSETBUFFER1MOVSI OFFSETBUFFER2然后 就可以用这些指针来间接寻址这些缓冲区 TYPE运算符返回一个数字值 它表示存储器操作数的类型部分 字节 字和双字的类型部分 分别是它们所占有的字节数 而指令单元的类型部分的值 没有实际的物理意义 LENGTH运算符返回一个与存储器地址操作数相联系的单元数 所定义的基本单元的个数 注意 要用LENGTH返回的存储区必须用DUP 来定义 否则返回值为1 故可以利用LENGTH运算符对计数器进行初始化 分析运算符SIZE返回一个为存储器地址操作数所分配的字节数 一般来说 若一个存储单元操作数X 则sizeX lengthX typeX IBM宏汇编中的合成运算符为PTR和THIS 它们能建立起一些新的存储器地址操作数 PTR运算符能产生一个新的存储器地址操作数 一个变量或标号 新的操作数的段地址和段内偏移量与PTR运算符右边的操作数的对应分量相同 而类型由PTR的左边的操作数指定 不像一个数据定义语句 PTR操作数并不分配存储器 它可以给已分配的存储器一个另外的定义 段交叉转移合成运算符THIS与PTR类似 也可以建立一个新的存储器地址操作数 并且不分配存储器 用运算符THIS建立起来的新的存储器地址操作数的类型在THIS中指定 而它的段地址和段内偏移量就是汇编时的当前值 THIS运算符 THIS运算符也可指定存储器操作数的类型 使用THIS运算符可以使标号或变量更具灵活性 例如 要求对同一个数据区既可以字节为单位 又可以字为单位进行存取 则可用以下语句 TAB1EQUTHISWORDTAB2DB100DUP 上面TAB1和TAB2实际上代表同一个数据区 其中共有100个字节 但TAB1的类型为WORD 字类型 而TAB2的类型为BYTE 字节类型 4 3 3段定义语句 8086的存储器是分段的 所以8086必须按段来组织程序和利用存储器 这就需要有段定义语句 段定义的主要命令有 1 SEGMENT 2 ENDS 3 ASSUME 4 ORG SEGMENT和ENDS语句把汇编语言源程序分成段 这些段就相应于存储器段 在这些存储器段中 存放相应段的目标码 汇编程序必须知道程序的段结构 并知道在各种指令执行时将访问哪一个段由段寄存器所指向 这个信息是由ASSUME语句提供的 通常在汇编语言的源程序中 至少要定义码段 指令段 堆栈段和数据段 有时还要定义附加段 每一个段必须有一个名称 如MY DATA MY CODE等 一个段由命令SEGMENT开始 由命令ENDS结束 它们必须成对出现 而且它们的语句中必须有名称 名称必须相同 最后用语句END来结束整个源程序 ASSUME语句 只是使汇编程序知道在程序执行时各个段寄存器的值 而这些段寄存器的实际值 除了码段寄存器CS以外 还必须在程序执行时 用MOV指令来赋给 一般来说 存储器段具体在哪儿是不重要的 可由汇编程序来选择 但是 在有些情况下 可能要给汇编程序一些约束 例如 不要使这个段与别的段搭接 保证这个段所用的第一个字节在偶数地址 这样对于一个字的访问可以在一个存储器读写周期完成 或 在下列地址开始这个段 可以把这些约束写入到源程序中 另一个语句ORG origin 它规定了段内的起始地址 伪指令ORG的一般格式为 ORG 表达式 此语句指定了段内在它以后的程序或数据块存放的起始地址 即以语句中的表达式的值作为起始地址 连续存放 除非遇到一个新的ORG语句 SEGMENT伪指令用于定义一个逻辑段 给逻辑段赋予一个段名 并以后面的任选项 定位类型 组合类型 类别 规定该逻辑段的其他特性 SEGMENT伪指令位于一个逻辑段的开始部分 而ENDS伪指令则表示一个逻辑段的结束 在汇编语言源程序中 这两个伪指令定义符总是成对出现的 二者前面的段名必须一致 两个语句之间的部分即是该逻辑段的内容 例如 对于代码段 其中主要有指令及其他伪指令 对于数据段和附加段 主要有定义数据区的伪指令等等 一个源程序中不同逻辑段的段名可以各不相同 1 定位 Align 类型定位类型任选项告诉汇编程序如何确定逻辑段的边界在存储器中的位置 定位类型共有以下四种 BYTE 边界起始地址 B 该类型表示逻辑段从一个字节的边界开始 即可以从任何地址开始 此时本段的起始地址可紧接在前一个段的后面 WORD 边界起始地址 0B 该类型表示逻辑段从字的边界开始 2字节为1个字 此时本段的起始地址必须是偶数 PARA 边界起始地址 0000B 该类型表示逻辑段从一个节 Paragraph 的边界开始 一节等于16个字节 也即段的起始地址能被16整除 故本段的起始地址 十六进制 应为 0H 如果省略定位类型任选项 则默认其为PARA PAGE 边界起始地址 00000000B 该类型表示逻辑段从页边界开始 一页等于256个字节 也即段的起始地址能被256整除 故本段的起始地址 十六进制 应为 00H 2 组合 Combine 类型SEGMENT伪指令的第二个任选项是组合类型 它告诉汇编程序当装入存储器时各个逻辑段如何进行组合 组合类型共有以下六种 1 不组合 如果SEGMENT伪指令的组合类型任选项缺省 则汇编程序认为这个逻辑段是不组合的 也就是说 不同程序中的逻辑段 即使具有相同的段名 也分别作为不同的逻辑段装入内存 不进行组合 但是 对于组合类型任选项缺省的同名逻辑段 如果属于同一个程序模块 则被集中成为一个逻辑段 2 PUBLIC 连接时 对于不同程序模块中的逻辑段 只要具有相同的段名 就把这些段集中成为一个逻辑段装入内存 3 STACK 组合类型为STACK时 其含意与PUBLIC基本一样 即不同程序中的逻辑段 如果段名相同 则集中成为一个逻辑段 不过组合类型STACK仅限于作为堆栈区域的逻辑段使用 顺便提一下 在执行程序 EXE 中 堆栈指针SP设置在这个集中以后的堆栈段的 最终地址 1 处 4 COMMON 连接时 对于不同程序中的逻辑段 如果具有相同的段名 则都从同一个地址开始装入 因而各个逻辑段将发生重叠 最后 连接以后段的长度等于原来最长的逻辑段的长度 重叠部分的内容是最后一个逻辑段的内容 5 MEMORY 该类型表示当几个逻辑段连接时 本逻辑段定位在地址最高的地方 如果被连接的逻辑段中有多个段的组合类型都是MEMORY 则汇编程序只将首先遇到的段作为MEMORY段 而其余的段均当作COMMON段处理 6 AT表达式 这种组合类型表示本逻辑段根据表达式的值定位段地址 例如AT8A00H 表示本段的段地址为8A00H 则本段从存储器的物理地址8A000H开始装入 3 类别 Class SEGMENT伪指令的第三个任选项是 类别 类别必须放在单引号内 类别 的作用是在连接时决定各逻辑段的装入顺序 当几个程序模块进行连接时 其中具有相同类别名的逻辑段被装入连续的内存区 类别名相同的逻辑段 按出现的先后顺序排列 没有类别名的逻辑段 与其他无类别名的逻辑段一起连续装入内存 例如 假设一个主程序中有五个逻辑段 段名和类别名分别为 STK1段 STACK CODE1段无DATA1段 BUFFER DATA2段 TABLE DATA3段 BUFFER 还有一个子程序 包括四个逻辑段 段名和类别名分别为 DATA4段 TABLE DATA5段 BUFFER STK2段 STACK CODE2段无 当将上述主程序和子程序进行连接时 两个程序模块中各逻辑段装入内存的顺序见图5 3 图5 3逻辑段按类别装入内存的示意图 SEGMENT伪指令后面还有三个任选项 定位类型 组合类型和 类别 在上面的格式中 它们都放在方括号内 表示可有可无 如果有 三者的顺序必须符合格式中的规定 这些任选项是给汇编程序 MASM 和连接程序 LINK 的命令 SEGMENT伪指令后面的任选项告诉汇编程序和连接程序 如何确定段的边界 以及如何组合几个不同的段等 下面分别进行讨论 4 3 4过程定义语句 过程是程序的一部分 它们可被程序调用 每次可以调用一个过程 当过程中的指令执行完后 控制返回调用它的地方 在8086中调用过程和从过程返回的指令是CALL和RET 这些指令可以有两种情况 段内的和段交叉的 段交叉指令把过程应该返回处的段地址和段内偏移量这两者都入栈保护 CALL指令 和退栈 RET指令 段内的调用与返回指令只入栈和退栈段内的地址偏移量 过程定义语句的格式为 PROCEDURE NAMEPROC NEAR 或PROCEDURE NAMEPROCFAR RETPROCEDURE NAMEENDP伪指令PROC与ENDP都必须有名称 两者必须成对出现 名称必须相同 利用过程调用语句可以把程序分段 以便于阅读 理解 调试和修改 若整个程序由主程序和若干个子程序组成 则主程序和这些子程序必须一起包含在码段中 除非用段交叉调用 主程序和各个子程序都作为一个过程 用上述的过程定义语句来定义 用段内CALL指令调用的过程 必须用段内的RET指令返回 这样的过程是NEAR过程 用段交叉CALL指令调用的过程 必须用段交叉RET指令返回 这样的过程是FAR过程 过程定义语句PROC和ENDP EndProcedure 限定了一个过程且指出它是一个NEAR或FAR过程 这在两方面帮助了汇编程序 4 3 5结束语句 除了一个例外 END结束语句 以外 每一个结束语句 TerminationStatements 都与某个开始语句成对出现 例如 SEGMENT和ENDS PROC和ENDP 惟一的例外就是END语句 它标志着整个源程序的结束 它告诉汇编程序 没有更多的指令要汇编了 END语句的格式是 END 表达式 其中 表达式必须产生一个存储器地址值 这个地址是当程序执行时 第一条要执行的指令的地址 汇编语言和DOS操作系统的接口当我们编写的汇编语言源程序是在DOS环境下运行时 必须了解汇编语言是如何同DOS操作系统接口的 当我们用编辑程序把源程序输入到机器中 用汇编程序把它转换为目标程序 用连接程序对其进行连接和定位时 操作系统为每一个用户程序建立了一个程序段前缀区PSP 其长度为256个字节 主要用于存放所要执行程序的有关信息 同时也提供了程序和操作系统的接口 操作系统在程序段前缀的开始处 偏移地址0000H 安排了一条INT20H软中断指令 INT20H中断服务程序由DOS提供 执行该服务程序后 控制就转移到DOS 即返回到DOS管理的状态 因此 用户在组织程序时 必须使程序执行完后能去执行存放于PSP开始处的INT20H指令 这样便返回到DOS 否则就无法继续键入命令和程序 DOS在建立了程序段前缀区PSP之后 就将要执行的程序从磁盘装入内存 在定位程序时 DOS将代码段置于PSP下方 代码段之后是数据段 最后放置堆栈段 内存分配好之后 DOS就设置段寄存器DS和ES的值 以使它们指向PSP的开始处 即INT20H的存放地址 同时将CS设置为PSP后面代码段的段地址 IP设置为指向代码段中第一条要执行的指令位置 把SS设置为指向堆栈的段地址 让SP指向堆栈段的栈底 取决于堆栈的长度 然后系统开始执行用户程序 为了保证用户程序执行完后能返回到DOS状态 可使用如下两种方法 1 标准方法首先将用户程序的主程序定义成一个FAR过程 其最后一条指令为RET 然后在代码段的主程序 即FAR过程 的开始部分用如下三条指令将PSP中INT20H指令的段地址及偏移地址压入堆栈 PUSHDS 保护PSP段地址MOVAX 0 保护偏移地址0PUSHAX 这样 当程序执行到主程序的最后一条指令RET时 由于该过程具有FAR属性 故存在堆栈内的两个字就分别弹出到CS和IP 从而执行INT20H指令 使控制返回到DOS状态 例如上面的多字节相加程序就是采用这种方法使控制返回到DOS状态的 返回DOS的标志就是程序运行完后出现一个DOS的标识符 如C 2 非标准方法也可在用户的程序中不定义过程段 只在代码段结束之前 即CODEENDS之前 增加两条语句 MOVAH 4CHINT21H则程序执行完后也会自动返回DOS状态 4 4指令语句 每一条指令语句 使汇编程序产生一条8086指令 一条8086指令是由一个操作码字段和一些由操作数寻址方式所指定的字段组成的 所以在IBM宏汇编的指令语句 必须包括一个指令助记符 以及充分的寻址信息以允许汇编程序产生一条指令 4 4 1指令助记符 大多数指令助记符 InstructionMnemonics 与8086指令的符号操作码名相同 某些附加的指令助记符 如NIL和NOP使得汇编语言更加通用 1 NOP NoOperation 指令助记符NOP 使汇编程序产生一字节指令 它使寄存器AX的内容自行交换 除了不做任何事以外 NOP并不浪费任何不做的时间 因为它并不做任何的存储器访问 NOP可以保留一些单元为以后填入指令用 另外 当需要精确的时间关系时 这也可以使程序的一部分放慢 2 保留空格 PlaceHolder NIL是使汇编程序不产生任何指令的惟一的指令助记符 与NOP指令相比较 NOP使汇编程序产生一条不做任何操作的指令 而NIL甚至连指令都不产生 NIL在汇编语言程序中是为标号保留空格的 如 CYCLE NILINCAX虽然它与以下语句等效 CYCLEINCAX但有了NIL 若以后需要的话 便于在INC指令前插入其他指令 4 4 2指令前缀 8086指令系统允许指令用一个或多个指令前缀 InstructionPrefixes 开始 有三种可能的前缀 1 段超越 Segmentoverride 2 重复 Repeat 3 锁定 Lock IBM宏汇编中允许的作为前缀的助记符如下 LOCKREP Repeat 重复 REPE 当相等时重复 REPNE 当不相等时重复 REPZ 当标志Z 1时重复 REPNZ 当标志Z 0时重复 段超越前缀是当汇编程序在汇编时认识到一个存储器访问需要这样一个前缀时 由汇编程序自动产生的 首先 它选择一个能使程序正常执行的段寄存器 汇编程序是基于前面的ASSUME语句所提供的信息来选择段寄存器的 我们也可以用包含有段寄存器的指令 来迫使选择一个实际的段寄存器 如其次 汇编程序决定在用所选择的段寄存器执行指令时 是否需要一个段超越前缀 4 4 3操作数寻址方式 8086CPU提供了各种操作数寻址方式 IBM宏汇编在写指令语句时 必须为每一种寻址方式表示一种表达式 立即寻址 ImmediateAddressing 寄存器寻址 RegisterAddressing 直接寻址 DirectAddressing 4 通过基址寄存器间接寻址 IndirectthroughBaseRegisterAddressing 5 通过变址寄存器间接寻址 IndirectThroughIndexRegisterAddressing 6 通过基址寄存器加变址寄存器间接寻址 IndirectthroughBaseRegisterPlusIndexRegisterAddressing 7 通过基址或位移量间接寻址8 通过基址寄存器加变址寄存器加位移量间接寻址 汇编程序在产生一条指令要涉及一个存储单元时 要用到关于这个存储单元类型的信息 在编写汇编语言的语句时 必须使汇编程序能确定类型 4 4 4串操作指令 汇编程序通常可以通过一个操作数自己的说明 来确定一个操作数的类型 从而帮助汇编程序确定当访问此操作数时应产生什么样的码 然而 当用一个间接寻址方式时 可能需要向汇编程序提供附加的信息 以帮助确定类型 串操作指令 StringInstructions 也需要这样的附加信息 考虑串操作指令MOVS 这条指令是把在数据段中的地址偏移量在SI中的存储单元的内容 传送给在附加段中的地址偏移量在DI中的存储单元 对于这样的指令 不需要规定任何操作数 因为这条指令对从哪儿传送到哪儿没有选择的可能 然而 这条指令可以传送一个字节也可以传送一个字 汇编程序就必须确定它的类型 才能产生正确的指令 为此 IBM宏汇编必须规定已经传送至SI和DI的项的类型 与MOVS指令类似 别的四个基本的串操作指令也包括有操作数 MOVS和CMPS有两个操作数 而SCAS LODS和STOS有一个操作数 也需要确定操作数的类型 一个完整的用汇编语言编写的源程序 应该是由可执行指令组成的指令性语句和由对符号定义 分配存储单元 分段等指示性语句组成 而且 一个完整的程序至少应该包含三种段 由源程序行组成的码段 堆栈操作所需要的堆栈段以及存放数据的数据段 汇编语言程序设计 通常 编制一个汇编语言程序应按如下步骤进行 明确任务 确定算法 绘流程图 根据流程图编写汇编语言程序 上机调试程序 图6 3标准流程图符号 6 2 1顺序程序设计 图6 4顺序结构流程图 例6 5试编制一程序 求出下列公式中的Z值 并存放在RESULT单元中 其中X Y的值分别存放在VARX VARY单元中 源程序编制如下 TITLEEXAMPLE 1DATASEGMENT 2VARXDW6 3VARYDW7 4RESULTDW 5DATAENDS 6STACK1SEGMENTPARASTACK 7DW20HDUP 0 8STACK1ENDS 9COSEGSEGMENT 10ASSUMECS COSEG DS DATA SS STACK1 11PROC1PROCFAR12START PUSHDS 13MOVAX 0 14PUSHAX 15MOVAX DATA 16MOVDS AX 17MOVDX VARX DX X 图6 5用户程序装入内存后的内存分配情况 结束用户程序 返回操作系统的另一个办法是用中断指令 INT21H 如使用这种办法 用户程序可以不设置过程 只要在用户程序结束时 用以下两条指令即可 MOVAH 4CH INT21H 这样 上述程序的代码段可以修改为 COSEGSEGMENT ASSUMECS COSEG DS DATA ASSUMESS STACK1 START MOVAX DATA MOVDS AX MOVDX VARX ADDDX VARY MOVCL 3 SALDX CL SUBDX VARX SARDX 1 MOVRESULT DX MOVAH 4CH INT21H COSEGENDS ENDSTART 例用查表的方法将一位十六进制数转换成与它相应的ASCII码 既然指定用查表的方法 那么首先要建立一个表TABLE 我们在表中按照十六进制数从小到大的顺序放入它们对应的ASCII码值 编制的源程序如下 DATASEGMENT TABLEDB30H 31H 32H 33H 34H 35H 36H 37H DB38H 39H 41H 42H 43H 44H 45H 46H HEXDB4 ASCIDB DATAENDS STACK1SEGMENTPARASTACK DW20HDUP 0 STACK1E
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GSK2636771-Standard-生命科学试剂-MCE
- 2025航天科工天隼实验室招聘4人模拟试卷附答案详解(黄金题型)
- 2025年河南省上蔡第一高级中学招聘教师30人模拟试卷及答案详解(网校专用)
- 2025年户外机柜温控节能项目合作计划书
- 安全培训效果点评课件
- 企业信誉与发展规划承诺函9篇
- 美食电商美食节促销计划
- 2025年甘肃省兰州眼科医院(兰州市第一人民医院眼科)招聘考前自测高频考点模拟试题参考答案详解
- 小学交通安全培训简报课件
- 2025届春季中核集团人才计划招聘模拟试卷附答案详解(突破训练)
- 肾病综合征课件
- 神经外科危重患者综合管理
- 2025年测试题及答案情侣
- (高清版)DB54∕T 0483-2025 《食用农产品快检数字化监管规范》
- 公安特费管理暂行办法
- 英语中考词汇教学课件
- 积压存货奖励管理办法
- 工程分包班组管理办法
- 2025年四川乐山市沙湾区铜河发展集团有限公司招聘考试试卷
- 高中化学必修二1.2《物质结构-元素周期律》
- 卒中后癫痫诊治的中国专家共识解读
评论
0/150
提交评论