前 言
本系列讲座的目的是帮助读者学习汇编语言程序设计,达到入门和提高。讲座以PC/486为背景,共分五讲:第一讲 概述;第二讲 指令系统;第三讲 汇编语言中的符号、表达式和伪指令;第四讲 程序设计的基本方法及举例;第五讲汇编语言程序的上机调试与技巧。每讲前,介绍该讲的主要内容,突出一个重点;每讲后给出小结,指出读者应掌握的知识。讲座汇集了经验,解答了学习汇编语言经常遇到的一些问题以及常见错误。讲座通过展示实例,通俗讲解汇编语言程序设计的方法和技巧。
第一讲 概述
本讲介绍汇编语言的特点、程序结构及其应用寄存器组。
汇编语言的特点与源程序结构
1.1 汇编语言的特点
让我们首先看一个使用机器语言及对应的汇编语言编写的一个例程序,其功能是在计算机显示器屏幕上显示一个字符:A。
机器语言 汇编语言
1011 0010 MOV DL,‘A’
0100 0001
1011 0100 MOV AH,02H
0000 0010
1100 1101 INT 21H
0010 0001
例子左边的二进制代码称为机器语言,这些代码存放在规定的存储单元中,微处理器查看这些单元,从中取出代码,判断其意图并加以执行。这些二进制代码之所以叫做“机器语言”是因为机器(微处理器)能理解它们,并能对它们进行处理。对于人来说,这些代码是很难理解和记忆的,需要经过专门训练才能翻译一个完全用二进制代码编写的程序,而微处理器却很容易对机器语言进行处理。与此相反,例子右边的那列由助记命令(用助记符代替操作码,用符号代替操作数)所组成的“汇编语言”对于微处理器来说都是不可理解的。把人们可理解的汇编语言翻译成微处理器可直接识别的机器语言,这个翻译过程称为汇编。完成汇编任务的程序称为汇编程序。汇编过程如图1-1所示。
图1-1 汇编过程示意
另一类程序语言称为高级语言,比如BASIC,PASCAL,C。这类语言虽然比较容易学习,开发周期短,但是用它们所编写的程序执行速度较慢,控制也不灵活。而汇编语言却具有对硬件的控制能力强、程序执行速度快、占用内存空间少等高级语言无法取代的优点,所以,汇编语言始终是程序设计的主要手段之一,汇编语言大量被应用在需要直接控制硬件的场合以及对程序执行时间和占用内存空间要求较高的场合。比如实时控制系统、实时通信系统、智能化仪器仪表及高性能软件等方面,也常被各种高级语言所嵌用。
汇编语言是一种面向机器的语言,这种语言可以直接使用寄存器、标志位、存储器等机器硬件系统的许多特性。为此学习汇编语言必须熟悉机器的内部结构,特别是微处理器和存贮器的结构。必须熟悉机器的指令系统。
1.2汇编语言程序的结构
下面通过一个简单实例来说明一个完整的汇编语言源程序的结构。
例: 内存中以FIRST和SECOND开始的单元中分别存放着两个8位压缩的10进制(BCD码)数,低位在前。编写程序求这两个数的压缩的10进制和,并存放到以THIRD开始的单元。
.MODEL SMALL ;定义内存模式
.DATA ;定义数据段
FIRST DB 31H,57H,38H,49H ;第一个加数
SECOND DB 25H,70H,15H,60H ;第二个加数
COUNT EQU $-SECOND
THIRD DB 5 DUP(?) ;需要5个字节存放和
.CODE ;定义代码段
START : MOV AX,@DATA
MOV DS,AX ;给DS和ES赋初值
MOV ES,AX
CLC ;最低字节相加无进位
CLD ;串操作地址按增量方向
MOV SI,OFFSET FIRST ;设置数据指针
MOV DI,OFFSET THIRD
MOV BX,OFFSET SECOND
MOV CX,COUNT ;8位10进制数,长4个字节
CYCLE: LODSB ;取第一个数
ADC AL,[BX] ;与第二个数相加
DAA ;把AL中的和调整成压缩BCD数
STOSB ;存结果
INC BX ;数据指针指向下一个字节
LOOP CYCLE ;循环
MOV AL,O
ADC AL,O
STSOB ;存最高进位
MOV AX,4C00H
INT 21H ;返回DOS
.STACK ;定义堆栈段
END START
由此可见:
(1)每个源程序开始必须使用存储模型说明伪指令,来描述程序采用的存储类型。如例程序中的 .MODEL SMALL。
(2) 源程序由若干个段组成。每个段都是以‘.’开始,如例程序中的.CODE(定义代码段);.DATA(定义数据段);.STACK(定义堆栈段)。
(3)每一段的开始,同时也表示上一段的结束。伪指令END说明最后一个段的结束。
(4)一个段又是由若干条语句组成。
(5)语句有两类:指令语句(如MOV、ADC)和伪指令语句(如DB、END),一个完整的源程序必须含有这两类语句。
应用寄存器组
处理器中有16个供应用程序员使用的寄存器,称为应用寄存器组。如图2-1所示。这16个寄存器可分为三组:
通用寄存器
段寄存器
标志寄存器和指令指针
图 2-1 应用寄存器组
(1)通用寄存器:八个32位的寄存器可供程序员随意使用。
(2)段寄存器:用于存放与存储器访问形式有关的段选择符。
(3)标志寄存器和指令指针:存放处理器的状态。
2.1通用寄存器
通用寄存器包括八个32位寄存器:EAX、EBX、ECX、EDX、EBP、ESP、ESI、EDI。这些寄存器用来存放逻辑运算和算术运算用的操作数,还可存放存储器操作数的地址(ESP除外)。为了和8086兼容,每个通用寄存器的低16位可以独立存取,此时,它们的名称分别为AX、BX、CX、DX、BP、SP、SI、DI。此外,为了和8080兼容,前四个寄存器的低八位和高八位也可独立存取,其名称分别为AL、BL、CL、DL、AH、BH、CH、DH,如图2-1所示。
2.2段寄存器
段寄存器包括六个16位段寄存器。它们分别是代码段寄存器CS,堆栈段寄存器SS,数据段寄存器DS、ES、FS、GS。
在实地址方式下,每个段的大小固定为64K(216)字节,与8086相同。把段寄存器的内容左移四位,就得到对应段的基地址,再加上偏移量,就得到存储单元的地址,这个地址称为物理地址。其公式为:物理地址=段寄存器的内容*16+偏移量
在保护方式下,每个段的大小是可以选择的,可从1到4G字节。为了描述每个段的性质(段基址、段限制及其它属性),为每个段定义了一个段描述符,并设置了六个段描述符寄存器,来对应六个段寄存器。这些段描述符构成了全局描述符表和局部描述符表。
在保护方式下,可通过段寄存器中的内容从描述符表中选择一个段描述符,根据段描述符,可以查到段基地址。
2.3标志寄存器
标志寄存器EFLAGS是一个32位的寄存器。有14个标志位,可分为三类:壮态标志(S)六个;控制标志(C)一个;系统标志(X)七个。壮态标志是CPU在执行指令过程中产生的;控制标志是由程序员通过指令预先设置的;系统标志和系统处在什么工作方式密切相关。标志寄存器中各位的含义如图2-2所示。
图2-2 EFLAGS(标志)寄存器
壮态标志用于记录指令操作的结果。各状态标志见表2-1。
表2-1 状态标志
名字 |
用途 |
置位的条件 |
OF |
溢出 |
结果超出正界限或负界限 |
SF |
符号 |
结果为负 |
ZF |
零 |
结果为零 |
AF |
辅助进位 |
第三位的进位输出(用于BCD) |
PF |
校验 |
结果的低字节具有的偶奇偶性(置位的位数是偶数) |
CF |
进位标志 |
结果的最高位有进位/借位 |
控制标志DF用于控制串操作指令中地址变化的方向。 DF=0时,串指针(SI/DI)自动增量。DF=1时,串指针(SI/DI)自动减量。
系统标志
IF: IF=1时,允许外部可屏蔽中断;IF=0时,禁止外部可屏蔽中断。
TF: TF=1时,CPU进入单步执行指令方式,用于观查每一条指令的执行情况。
NT: NT=1时,表示当前的任务嵌套在另一任务内,若执行IRET指令,则转移到前一个任务。
IOPL:用于指明执行I/O指令的特权级。IOPL占两位,可表示0—3四个特权级。
RF: 用于控制是否接受调试故障。RF=0,接受;RF=1,忽略。
VM: VM=1时,CPU工作在虚拟8086方式。VM=0时,CPU工作在一般的保护方式下。
AC: AC=1时,若进行未对齐的地址访问,则产生异常中断17。所谓未对齐的地址访问,是指访问字数据时,地址不是偶数;访问双字数据时,地址不是4的整数倍;访问8字节数据时,地址不是8的整数倍;
2.4指令指针
指令指针EIP是一个32位的寄存器,用来存放下一条要执行的指令的地址的偏移量。该偏移量是相对于代码段(CS)基地址的值。为了和8086兼容,EIP的低16位可作为独立指针,称为IP。此时,寻址范围64K字节。
小结
了解使用汇编语言的场合和一个完整的源程序结构;掌握应用寄存器组的组成和用途。
|