2.1 数制系统
大多数现代计算机系统都不使用十进制(以10为基数),而是通常采用二进制或者二进制补码(two's complement)的数制系统。
2.1.1 十进制数制系统的回顾
长期以来,人们一直使用十进制数制系统,因此可能会想当然地认为所有数字都是十进制数。现在,当看到像123这样的数字时,不要去考虑数值123,而是在大脑中考虑它总共代表多少项。实际上数字123在十进制数制系统中的表示如下:
(1×102)+(2×101)+(3×100)
或者
100+20+3
在十进制的位置数制系统中,小数点左侧的每一位数字都代表一个数值,它们是0~9之间的数字乘以10的递增次方幂;小数点右侧的每一位数字也都代表一个数值,它们是0~9之间的数字乘以10的递增负次方幂。例如,123.456可以表示为:
(1×102)+(2×101)+(3×100)+(4×10-1)+(5×10-2)+(6×10-3)
或者
100+20+3+0.4+0.05+0.006
2.1.2 二进制数制系统
在大多数现代的计算机系统中都采用二进制逻辑进行运算。计算机使用两个电平(通常是0V和+2.4~5V)表示数值,这两个电平正好可以表示两个不同的数值。这两个数值可以是任意两个不同的数值,但通常表示二进制数制系统中的两个数值0和1。
二进制数制系统与十进制数制系统的原理类似,不同之处在于二进制数制系统中仅存在0和1(而不是0~9),并且使用的是2的幂(而不是10的幂)。因此,将二进制数字转换为十进制数字非常容易。对于二进制字符串中的每个1,都要乘上2n,其中n是从0开始计数的1所在的位置。例如,二进制数110010102可以表示为:
(1×27)+(1×26)+(0×25)+(0×24)+(1×23)+(0×22)+(1×21)+(0×20)
=12810+6410+810+210
=20210
总而言之,首先必须找到所有2的幂,然后将这些幂相加,结果就等于十进制数字。
将十进制数字转换为二进制数字要稍微复杂一些,一种简单方法是“偶/奇—除2”(even/odd—divide-by-two)算法。该算法使用以下的步骤。
(1)如果数字为偶数,则得到一个0。如果数字为奇数,则得到一个1。
(2)将数字除以2,并舍弃小数部分或余数。
(3)如果商为0,则算法完成。
(4)如果商不是0并且是奇数,则在当前二进制串前插入1;如果数字为偶数,则在当前二进制串前面加0。
(5)返回到步骤(2),并重复操作步骤。
虽然在高级计算机程序设计语言中,二进制数不太重要,但它们在汇编语言程序中随处可见。所以读者必须熟悉二进制数。
2.1.3 二进制约定
从最纯粹的意义上讲,每个二进制数都可以包含无限多位的数字,或者称为二进制位(bit,简称位,是binary digit的缩写)。例如,我们可以使用以下任意一种方式来表示数字5:
101 00000101 0000000000101 … 000000000000101
二进制数之前可以包含任意数量的前导0,而不改变其值的大小。由于x86-64通常使用8位的组,所以我们将使用前导0把所有二进制数扩展到4或者8的倍数位。按照这个约定,我们将5表示为01012或000001012。
对于较大的二进制数,为了增加其可读性,我们将每4位分为一组,组之间使用下划线分隔。例如,我们将1010111110110010写成1010_1111_1011_0010的形式。
注意:MASM不允许在二进制数的中间插入下划线。在较大数内部使用下划线分隔只是本书为便于阅读而采用的约定。
我们将按如下方式对每个二进制位进行编号。
(1)二进制数中最右边的位编号为第0位。
(2)从右向左的每一个二进制位连续编号。
一个8位的二进制数使用第0位~第7位的位置编号:
X7X6X5X4X3X2X1X0
一个16位的二进制数使用第0位~第15位的位置编号:
X15X14X13X12X11X10X9X8X7X6X5X4X3X2X1X0
一个32位的二进制数使用第0位~第31位的位置编号,依此类推。
第0位称为低阶(low-order,LO)位,有些人将其称为最低有效位(least signifcant bit)。最左边的位称为高阶(high-order,HO)位,或者称为最高有效位(most signifcant bit)。我们将通过中间位各自的位置编号来引用这些位。
在MASM中,可以将二进制数指定为以字符b结尾的0或1串。请记住,MASM不允许在二进制数中使用下划线。