汇编语言程序设计(第3版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第1章 基础知识

本章提供了学习汇编语言程序设计所需的一些基础知识。首先对汇编语言程序设计进行了概述,其次对计算机常用的几种数制及其相互间的转换方法进行了讲解,并且介绍了数值数据和非数值数据在计算机中的表示方法。

1.1 汇编语言与汇编语言程序设计

1.1.1 汇编语言

计算机程序设计语言是人机交流的重要工具,可分为机器语言、汇编语言和高级语言。

机器语言是机器指令的集合,是一种面向机器的程序设计语言。机器指令是由0和1构成的二进制代码,不同种类的计算机具有各自的机器语言。其优点是可为计算机直接接受,用其编写的机器语言程序执行速度快,占内存空间小,可充分利用计算机的硬件特性;缺点是指令难记,用其编写的机器语言程序难以阅读且通用性差。

高级语言是面向问题求解过程或面向对象的程序设计语言。典型的高级语言有Pascal,FORTRAN,C++,Java等。高级语言接近于人类的自然语言,而且通用于各种计算机。其优点是易学易记,用其编写的高级语言程序易读易改,通用性强;其缺点是高级语言程序需经过编译或解释方能被计算机接受,执行速度慢,占内存空间大,不能直接利用计算机的硬件特性。

汇编语言又称为符号语言,实际上是一种符号化的机器语言。它将机器指令的操作码、操作数由二进制代码改为人们所熟悉的符号,例如

     ADD AL,5

表示将数字5加到AL中。汇编语言程序需经过汇编才能为计算机接受,这一点不如机器语言方便。虽然所用符号为人们所熟悉,然而不如高级语言那样接近人类的自然语言,程序编写和交流较为困难。除此以外,汇编语言几乎具备了机器语言的所有优点,一定程度上弥补了机器语言的缺陷,而且不存在高级语言的上述缺点。可以认为,汇编语言是目前使用的唯一直接利用计算机硬件特性的程序设计语言。

1.1.2 汇编语言程序设计

汇编语言程序设计是指使用汇编语言设计程序的过程。为什么要学习汇编语言程序设计?其原因至少有以下几点。

(1)通过汇编语言程序设计,人们可以高效地使用计算机解决现实问题。在解决同一现实问题时,汇编语言程序与高级语言程序相比,占用内存更小,执行速度更快。

(2)通过汇编语言程序设计,人们可以直接利用计算机的硬件特性,准确计算解决某一问题所需的时间,从而可实现实时控制。这一点是高级语言程序难以替代的。

(3)进行汇编语言程序设计,必然要从原理上认识、理解计算机的工作过程。因此,学习汇编语言程序设计不仅可以掌握一种高效的程序设计方法,而且对于学习计算机组成原理、计算机原理也大有帮助。

1.2 进位计数制

进位计数制是计数的一种方法。人们普遍习惯的进位计数制为十进制。十进制数的基为10,有10个数码:0、1、2、3、4、5、6、7、8及9,遵循逢十进一的规则。二进制数的基为2,有2个数码:0、1,遵循逢二进一的规则。以此类推,N进制数的基为N,有N个数码:0、1、2、…、N-1,遵循逢N进一的规则。常用的几种进位计数制的情况如表1.1所示。

表1.1 常用的进位计数制

1.2.1 常用计数制及其数的算术运算

1. 十进制(Decimal)

首先观察以下十进制数的组成:

361.905D=3×102+6×101+1×100+9×10-1+0×10-2+5×10-3

不难看出每一个数码根据它在这个数中所处的位置(数位)来决定实际数值。事实上,任意一个正的十进制数S=Kn-1Kn-2K0K-1K-2K-m+1K-m都可以表示成以下形式:

S=Kn-1×10n-1+Kn-2×10n-2+…+K1×101+K0×100+K-1×10-1+…+K-m+1×10-m+1+K-m×10-m

其中Ki可以是0至9这十个数码中的任意一个,mn均为自然数,10i称为权。一般而言,一个正的N进制数S=Kn-1Kn-2K0K-1K-2K-m+1K-m可以表示为以下通用形式:

其中Ki可以是0至N-1中任意一个数字,mn均为自然数,Ni为各数位相应的权。

2.二进制(Binary)

在日常生活中,存在着大量的两种对立的现象,例如:是和非,开和关,通和断。电子元件、物理器件中两种状态易于实现,如电压、电流的有和无,晶体管的导通和截止,这两种状态是非常稳定的,而找到8种、10种或16种稳定的状态则要复杂得多,所以计算机中采用二进制作为进位数制,以便于存储及计算的物理实现。

二进制数与人们常用的十进制数的对照关系如表1.2所示。

表1.2 常用进位计数制对照表

一个二进制数也可以用上述通用形式来表示。例如:

11101.011B=1×24+1×23+1×22+0×21+1×20+0×2-1+1×2-2+1×2-3

二进制数的算术运算与十进制数的算术运算类似,区别仅在于该运算遵循逢二进一的规则。

【例1.1】(1)1101B+1011B=11000B

(2)1101B-1011B=0010B

(3)1101B×1011B=10001111B

(4)1111B÷101B=11B

3. 十六进制(Hexadecimal)

十六进制数采用0~9,A~F十六个数码,这里A表示10D,B表示11D,C表示12D,D表示13D,E表示14D,F表示15D。

十六进制数与人们常用的十进制数的对照关系如表1.2所示。

一个十六进制数也可以用上述通用形式来表示。例如

6B.0CH =6×161+B×160+0×16-1+C×16-2

十六进制数的算术运算与十进制数的算术运算类似,区别仅在于该运算遵循逢十六进一的规则。

【例1.2】(1)8A04H+110CH=9B10H

(2)8A04H-110CH=78F8H

在汇编语言程序中,数据通常采用十六进制形式,汇编语言的调试、列表文件中显示的数据也都是使用十六进制形式,所以有必要熟练掌握这种数制及其数的运算。

4.八进制(Octal)

八进制数采用0~7八个数码,与十进制数的前八个数码一一对应,如表1.2所示。

一个八进制数也可以用上述通用形式来表示。例如

36.53Q=3×81+6×80+5×8-1+3×8-2

1.2.2 数制转换

1. 非十进制数→十进制数

非十进制数转换为十进制数的方法是:将非十进制数用上述通用形式表示,即按权展开,计算的结果即为十进制数。不管非十进制数是否带有小数部分,均可用这种方法转换。

【例1.3】1010110B=1×26+0×25+1×24+0×23+1×22+1×21+0×20=86D

4D.8H=4×161+13×160+8×16-1=77.5D

1362Q=1×83+3×82+6×81+2×80=754D

2. 十进制数→非十进制数

十进制数转换为二进制、八进制及十六进制等非十进制数的工作可分为整数的转换和小数的转换两种情况。一个十进制数与其对应的非十进制数相比,两者的整数部分和小数部分分别相等。于是,将一个十进制数转换为非十进制数时,可以对其整数部分和小数部分分别作转换,将两个转换结果结合起来就可以得到对应的非十进制数。

(1)十进制整数→非十进制整数

十进制整数转换为二进制、八进制及十六进制等非十进制整数可以采用除基取余法或减权记位法。前一方法较易掌握,但使用时较烦琐;后一方法使用时较方便,但需要熟悉非十进制各数位对应的权值。

① 除基取余法。将十进制整数及此间产生的商不断除以非十进制数的基,直至商为0为止,并记下每一次相除所得到的余数,按照从后往前的次序,将各余数作为Kn-1Kn-2K0,从而构成对应的非十进制数。

【例1.4】将233D转换为十六进制数。

按照题目要求,基应取16,具体转换过程如下:

转换结果为:233D=E9H。

【例1.5】将233D转换为二进制数。

按照题目要求,基应取2,具体转换过程如下:

转换结果为:233D=11101001B。

② 减权记位法。减权记位法常用于十进制数到二进制数的转换,对于十进制数到其他进制数的转换使用这种方法则不够方便。这里仅介绍十进制数到二进制数转换时,减权记位法的具体内容。

将十进制整数与其最相近的权值2n-1做比较,前者不小于后者则减去2n-1,并在n-1位记1;否则在n-1位记0。然后再与2n-2做比较并做相同的工作,直至最低位被记为1或0。从n-1位、n-2位直至最低位所记的1或0就构成了二进制数Kn-1Kn-2K0。通常第1次比较所用的2n-1取做小于等于十进制整数的最大二进位权值。

【例1.6】将233D转换为二进制数。

由于27<233D<28,故开始用做比较的数值取27

具体转换过程如下:

转换结果为:233D=11101001B。

【例1.7】将130D转换为二进制数。

考虑到130D为128D与2D之和,即为27与21之和,于是对应的二进制数K7K6K0K7=1,K1=1,其余位均为0,也即转换结果为130D=10000010B。

由该例可见,在熟悉二进制各数位对应的权值的基础上,参照减权记位法可以方便地进行十进制整数到二进制整数的转换。

(2)十进制小数→非十进制小数

十进制小数转换为二进制、八进制及十六进制等非十进制小数可以采用乘基取整法或减权记位法。前一方法较易掌握,但使用时较烦琐;后一方法使用时较方便,但需要熟悉非十进制数各数位对应的权值。

① 乘基取整法。将十进制小数以及此间产生的小数部分不断乘以非十进制数的基,并记下每次相乘所得到的整数部分,直至积的小数部分为0为止,按照从前往后的次序,将各整数部分作为K-1K-2,…K-m,就构成了对应的非十进制数K-1K-2K-m

【例1.8】将0.6875D转换为二进制数。

按照题目要求,基应取2,具体转换过程如下:

转换结果为:0.6875D=0.1011B。

【例1.9】将0.6875D转换为八进制数。

按照题目要求,基应取8,具体转换过程如下:

转换结果为:0.6875D=0.54Q。

当一个十进制小数对应的非十进制小数的位数过多时,可根据需要取前若干位作为近似结果。

② 减权计位法。与上述十进制整数转换为二进制整数时使用的减权计位法类似,但有两点区别:其一,十进制小数首先应与2-1比较,然后与2-2比较,依次类推;其二,有时要根据需要,取部分小数位作为近似转换结果。

【例1.10】将0.6875D转换为二进制数。

具体转换过程如下:

转换结果为:0.6875D=0.1011B。

如前所述,将一个十进制数转换为非十进制数时,可以对其整数部分和小数部分分别作转换,然后将整数部分和小数部分的转换结果结合成为最终结果。

【例1.11】将233.6875D转换为二进制数。

由前面的例题可知:

233D=11101001B

0.6875D=0.1011B

于是转换结果为:233.6875D=11101001.1011B。

3.二进制数←→ 八进制数、十六进制数

由于一位八进制数对应三位二进制数,一位十六进制数对应四位二进制数,于是二进制数与八进制数、十六进制数之间的转换比较简单。

(1)二进制数→八进制数、十六进制数

将二进制数由小数点向左右每三位分为一组(不足三位则用0补充),每一组用对应的八进制数码表示,即可得到对应的八进制数。类似地,将二进制数由小数点向左右每四位分为一组(不足四位则用0补充),每一组用对应的十六进制数码表示,即可得到对应的十六进制数。

【例1.12】将01011101.01B分别转换为八进制数和十六进制数。

          01011101.01B = 001011101.010B = 135.2Q
          01011101.01B = 01011101.0100B= 5D.4H

说明:在分组中若不足三位或不足四位时,一定要用0补充,否则极易出错。就该例而言,若不注意这一点,就极易将结果错写为135.1Q和5D.1H。

(2)八进制数、十六进制数→二进制数

将八进制数的每一位数用三位二进制数码表示,即可得到对应的二进制数。类似地,将十六进制数的每一位数用四位二进制数码表示,即可得到对应的二进制数。必要时可以去掉转换结果中的前0和尾0。

【例1.13】分别将45.4Q和27CH转换为二进制数。

          45.4Q=100101.100B=100101.1B
          27CH=001001111100B=1001111100B

从以上介绍可以看出,在将十进制数转换为非十进制数时,转换为二进制数较为简单,转换为八进制数、十六进制则较为复杂。考虑到二进制数转换为八进制数、十六进制数比较简单,故在需要将十进制数转换为八进制数、十六进制数时,可以先将其转换为二进制数,然后再由二进制数转换为八进制数、十六进制数。

【例1.14】将233.6875D转换为十六进制数。

首先将233.6875D转换为二进制数,由【例1.11】可知:

          233.6875D = 11101001.1011B

然后将11101001.1011B转换为十六进制数。

          11101001.1011B = E9.BH

于是十进制数到十六进制数的转换结果为:233.6875D = E9.BH

1.3 计算机中数和字符的表示

人们在使用计算机时,需要计算机不仅能处理数,即数值数据,而且能处理非数值数据,如字符、声音和图像等。虽然非数值数据在计算机中也是以二进制代码的形式存储,但它们的实际意义与数值数据不同。

1.3.1 数的表示

1. 机器数与真值

在本书前面的介绍中,均将数视为无符号数。例如,10100010B的每一位二进制数码均被视为数值,其对应的十进制数为162。有符号数在计算机中如何表示?首先需要解决数符如何表示的问题。在计算机中实际采用数值化的方法来表示数符,通常用0表示正,用1表示负。这样表示的数称为机器数,而人们所习惯的用+、-分别表示正、负的数称为真值。机器数的位数与计算机的字长有关,例如

这里机器数采用原码表示。实际上,机器数还可以采用补码、反码表示。

2.原码

原码的最高位表示真值的数符,其余位为数值位,且与真值的数值位相同,必要时在数值位前加上前0。

数的原码表示具有直观、与真值的转换方法简单等优点,但是原码有着算术运算复杂的缺陷。与手算相同,做加法运算时,首先要判断两数的数符,同号则相加,异号则相减。做减法运算时,还必须比较两数的绝对值,用较大的绝对值减去较小的绝对值,差的数符则采用绝对值较大者的数符。以上的算法对于硬件实现来说比较困难。

3.补码

补码的引入,是为了简化减法运算。补码的概念在日常生活中经常用到,例如手表的校时。假定手表停在11时,而标准时间为9时,可以使用两种校时方法:一种方法是逆时针调2小时,即11-2=9;另一种方法是顺时针调10小时,在调至12时后则为0时,即到12时时归零,因此有11+10=9(称为模加)。于是,就手表校时而言有:

这里12称为模,10称为2的补数。由此看出,减去一个数等价于加上该数的补数。下面介绍计算机中使用的补码的含义、求取方法及其运算。

(1)补码定义

当一个数为正数,则其补码就是该数本身;为负数,则其补码等于模值与该数绝对值之差。式中的n为补码的位数。

(2)根据真值求补码

根据补码定义可以求取一个数的补码,然而还可以采用更为简便的方法。求取一个数的n位补码的简便方法是:对于正数,通过补前0,将其数值部分补至n位即可;对于负数通过补前0,将其数值部分补至n位,然后按位取反并在末位加1即可。

【例1.15】求出以下各数的8位补码:

          +1000011B,-111000B,+1111111B,-10000000B,0

① 将+1000011B的数值部分通过补前0达到8位,即可得到其补码:

          [+1000011B]=01000011B

② 将-111000B的数值部分通过补前0达到8位,即00111000B。

          按位取反后得到:11000111B
          末位加1后得到:11001000B
          [-111000B]=11001000B

③ 将+1111111B的数值部分通过补前0达到8位,即可得到其补码:

          [1111111B]=01111111B

④ -10000000B的数值部分已达8位,即10000000B。

          按位取反后得到:01111111B
          末位加1后得到:10000000B
          [-10000000]=10000000B

⑤ 用同样方法不难求得:

          [0]=0

(3)根据补码求真值

补码最高位为0,则真值数符为“+”,真值数值位与补码其余位相同;补码最高位为1,则真值数符为“-”,将补码所有位按位取反且末位加1后就可得到真值的数值位。

用这种方法可以方便的将【例1.15】中求得的补码还原为对应的真值。

(4)补码的表示范围及补码的扩展

① 补码的表示范围。若要求给出+10000000B和-10000100B的8位补码,结果如何?显然,将求不出正确的结果。原因在于,这两个数超出了8位补码所能表示的范围-128~+127。一般而言,n位补码所能表示的范围为-2n-1~+2n-1-1。在计算机中,n常取8,16,32等。以上两个数可以表示为16位补码:

[+10000000B]=0000000010000000B

[-10000100B]=1111111101111100B

② 补码的扩展。为了满足进行算术运算等方面的需要,有时要求将一个补码扩展成双倍位数,比如由8位补码扩展为16位补码,由16位补码扩展为32位补码等。扩展方法是:将扩展的各位都置为原来补码的最高位。

例如:[+1000011B]=01000011B=0000000001000011B

[-111000B]=11001000B=1111111111001000B

(5)补码的加减法运算

补码加法规则:[X+Y]=[X]+[Y]

补码减法规则:[X-Y]=[X]+[-Y]

由此可见,使用补码可以将减法运算转换成加法运算,避免了前述减法运算中的困难。

【例1.16】补码加法运算。

上述②、④中从最高位向前的进位由于位数的限制而自动丢失,但这并不影响运算结果的正确性。

【例1.17】补码的减法运算。

在计算机中,补码减法是通过对减数求补后把减法转换为加法进行的。①、④中的最高位向前位的进位同样自动丢失,而不影响运算的结果。

4.反码

反码的最高位表示真值的数符,0表示正,1表示负。当反码最高位为0,则其余位与真值的数值位相同;当反码最高位为1,则其余位是真值的数值位按位取反后的结果。

5.BCD码

十进制小数和二进制小数相互转换时可能产生误差,而且日常习惯使用的是十进制,计算机中内部采用的是二进制。为方便十进制和二进制之间的转换,计算机允许内部采用一组四位二进制数来表示一位十进制数,组间仍然采用“逢十进一”的规则进行。这种采用二进制表示的十进制数编码称为BCD码(Binary Coded Decimal)码。该编码的方法和使用详见本书第五章。

1.3.2 字符的表示

计算机只能识别二进制数,因此计算机中的数字、字母、符号、控制符、汉字等也必须采用二进制进行编码。

1.ASCII码

非汉字常用字符包括:

字母:A,B,…,Z;a,b,…,z

数字:0,1,…,9

专用符号:+,-,*,/ …

为了使计算机硬件能够识别和处理这些字符,必须对字符按一定规则用二进制编码,目前广泛使用的是ASCⅡ码(美国国家标准信息交换码见附录B),这种代码用一个字节表示一个字符,最高位一般为校验位。

2.汉字编码

有了ASCII码,计算机就能处理数字和英文字母等字符,但是还不能处理汉字字符。为了使计算机能够处理汉字信息,就必须对汉字也进行编码。

(1)GB2312汉字编码

我国于1981年颁布了第一个国家标准——《信息交换用汉字编码字符集·基本集》(GB 2312)。该标准选出6763个常用汉字和682个非汉字字符,为每个字符规定了标准代码,以便在不同的计算机系统之间进行汉字文本的交换。

(2)GBK汉字内码扩充规范

GB 2312只有6763个简体汉字,在许多处理中有很大缺憾,如户籍中的人名、地名等。GBK是我国1995年发布的又一个汉字编码标准,一共有21003个汉字和883个图形符号,与GB 2312国标汉字字符集及其内码保持兼容,增加了大量了繁体字和符号。

(3)GB18030汉字编码标准

2000年我国政府发布新的汉字国家标准,解决GBK与台湾和香港地区Big5汉字编码不兼容的问题,同时也与国际标准化组织(ISO)制订的全球集中统一编码UCS-2接轨,保护了已有的大量中文资源。GB 18083标准与GB 2312标准和GBK标准保持向下兼容,扩充了UCS中其他字符。

习题

1.1 将下列十进制数转换为二进制数和十六进制数。

(1)(369)D =( )B =( )H

(2)(355)D =( )B =( )H

(3)(127)D =( )B =( )H

(4)(1000)D =( )B =( )H

1.2 将下列二进制数转换为十六进制数和十进制数。

(1)(1011110111)B=( )H=( )D

(2)(11000100101)B=( )H=( )D

(3)(10000000)B=( )H=( )D

(4)(11100101)B=( )H=( )D

1.3 下表给出了十进制数,请写出与之对应的二进制真值和8位补码。

1.4 下列各数均为十进制数,请用8位补码计算下列各题,并用十六进制数表示其运算结果。

1)69-48

2)-69+48

3)-69-48

1.5 分别将下列各数看作无符号数和补码,则各自对应的十进制数是什么?

1)98H

2)31H

3)FFH

4)80H

1.6 如果用16位存储一个无符号数,这个数的范围是什么?如果存储放入是一个补码表示的有符号数,那么这个数的范围是什么?

1.7 请写出下列字符串的ASCII码值。

            'Hello'
            'Please  give  me  $10.'