Assembly 移位操作
汇编语言允许程序员对数据的单个比特位进行操作。一个最常见的的位操作称为移位。移位操作移动某一个数据的比特位的位置。移位可以是向左移(也就是:向最高有效位移动),也可以向右移(最低有效位)。
逻辑移位
逻辑移位是移位中最简单的类型。它以一种最直接的方式进行移位操作。图3.1展示了一个字节的移位操作的例子。
注意:新进来的比特位总是为0。SHL 和SHR 指令分别用来执行逻辑左移和逻辑右移。这些指令允许你移动任意的位数。位数可以是一个常量,也可以是储存在CL寄存器的值。最后从数据中移出的比特位储存在进位标志位中。这有一些代码例子:
移位的应用
快速的乘法和除法是移位操作最普遍的应用。回忆在十进制系统中,乘以和除以10的几次方是非常简单的,只是移动位而已。在二进制中,乘以和除以2的几次方也是一样的。例如:要得到二进制数10112(或十进制11)的两倍,只需向左移动一位,得到101102 (或22)。一个除以2的几次方的除法的商相当于一个右移操作的结果。仅仅是除以2,向右移动一位;除以4(22),向右移动2位;除以8(23,向右移动3位,等等。移位指令非常基础而且比功能相同的MUL 和DIV 指令执行要快得多!
实际上,逻辑移位只可以用于无符号数的乘法和除法。一般它们不能应用于有符号数。考虑两个字节的数值FFFF(有符号时为¡1)。如果它向右逻辑移动一位,结果是7FFF,也就是+32; 767!另一种类型的移位操作可以用在有符号数上。
算术移位
这些移位操作是为允许有符号数能快速地执行乘以和除以2的几次方的操作而设计的。它们保证符号位能被正确对待。
SAL 算术左移(Shift Arithmetic Left) - 这条指令只是SHL的同义词。它实际上被编译成与SHL一样的机器代码。只要符号位没有因移位而改变,结果就将是正确的。
SAR 算术右移(Shift Arithmetic Right) - 这是一条新的指令,它不会移动操作数的符号位(也就是: 最高有效位)。其它位被正常移动,除了从左边新进来的位通过复制符号位(也就是说,如果符号位为1,那么新的位值也同样为1)得到外。因此,如果一个字节使用这条指令来移位,只有低7位会被移动。就像其它移位指令一样,最后移出的位储存在进位标志位中。
循环移位
循环移位指令像逻辑指令一样运作,除了把从数据的一端移出的比特位又移入到另一端外。因此,数据好像被当作一个循环结构体一样对待。ROL和ROR 是两个最简单的循环移位指令,它们分别执行左移和右移操作。就像其它移位指令一样,这些移位指令把循环移出的最后一个比特位复制到进位标志位中。
有两个额外的循环指令用来在数据和进位标志位之间移动比特位,它们称为RCL 和RCR。例如,如果AX寄存器用这些指令来移位,那么有17位用来得到AX,进位标志位也包括在循环中。
简单应用
这有一个代码小片断,它用来计算在EAX寄存器里\on"(也就是: 1)的比特位有多少个。
上面的代码毁掉了在EAX中的初值(循环之后,EAX的值为0)。如果你想保留EAX中的值,那么用rol eax, 1替换第四行即可。