每种汇编语言都有进行操作数移位的指令,移位和循环移位指令在控制硬件设备、加密数据,以及实现高速的图形操作时特别有用。本章讲述如何进行移位和循环移位操作以及如何使用移位操作进行高效的乘法和出发运算。
接下来,我们将探究IA-32指令集中的乘法和出发指令,Intel根据运算是有符号还是无符号的对乘法和出发进行分类。本章还讲述如何把C++中的数学表达式翻译成汇编语言。编译器把符合表达式分解翻译成一系列机器指令,模拟编译器有助于理解其工作机制,同时也有助于更好地对汇编语言代码进行手工优化。通过本章的学习,读者对操作符优先级以及寄存器的优化(在机器层)的机制将有更深入的理解。
是否思考过计算机是如何加减多字整数?本章中讲述的ADC(带进位加)指令和SBB(带进位减)指令是的处理任意大小的整数更容易一些。在本章最后,将讲述Intel的一些专门处理压缩十进制整数数字字符串的算术指令。
和第6章介绍的位操作指令一样,移位指令也是最具汇编语言特性的指令。移位的含义是在操作数内向左或者向右移动数据位,Intel提供了多种移位指令,表中所有的移位指令都影响溢出标志和进位标志。
对于一个数字来说有两种最进本的移位操作。第一种为逻辑移位,即以0填充最后移出的位。在下图中,一个逻辑右移移位,请注意位7被赋值0。
假设二进制值11001111向右移动一位,那么得到0110111,最低位数据移入进位标志。
另一种移位类型成为算术移位,最后移出去的位用数字原来的符号位填充。
例如,二进制11001111的符号位是1,当算术右移一位的时候,就变成了11100111。
SHL指令对目标的操作数进行逻辑左移操作,最低位以0填充,溢出的最高位放在进位标志(CF),原来进位标志中的值将丢失。
二进制11001111左移移位就变成了10011110。
SHL指令的第一个操作数是目的操作数,第二个操作数是移位的位数:
SHL 目的操作数,移位位数
SHL指令允许使用下面的操作数类型:
SHL reg ,imm8
SHL mem ,imm8
SHL reg ,CL
SHL mem ,CL
Intel8086/8088处理器要求imm8必须等于1,从80286及以上的处理器开始,
imm8可以是0~255之间的整数。在任何Intel处理器上,都可以使用CL存放移位位数。这里列出的格式也适用于SHR SAL SAR ROR ROL ROC和RCL指令。
例子:在下面的指令中,BL被左移一位。最高位被复制到进位标志中,最低位被清零。
mov bl ,8fh
shl bl ,1 CF,BL = 1,00011110b
多次移位:一个值多次左移试时,进位标志中的值是最后移出最高有效位(MSB)的数据位。在下面的例子中,进位标志的值是位6(0)而非位7的值:
mov al ,10000000b
shl al ,2 ;CF = 0
右移也遵循同样规则。
快速乘法:使用SHL指令可以进行2的次幂的高速乘法操作。任何操作数左移n位就相当于乘以2的n次方。
SHR指令是逻辑右移,和逻辑左移格式什么完全一样。这里不再介绍。
SAL指令与SHL指令等价(这句话我纠结了好久,上面明明说算术移位是符号位填充,所以我会认为11110000算术左移之后是11100001结果却是11100000果真和SAL一样)。SAR指令对目的操作数执行算是右移操作:
SAR,SHR指令的格式与SHL,SHR指令的格式相同,移位动作可以根据第二个操作数中的计数进行重复:
SAR 目的操作数,移位位数
下面的例子显示了SAR复制符号位的情况,AL中的值在右移操作的前后都是负数:
mov al ,0f0h ;al = 11110000b (-16)
sar al ,1 ;al = 11111000b(-8) CF = 0
有符号数的除法:使用SAR指令可以对有符号数进行除以我的次幂的快速操作。
mov dl ,-128 ;dl = 10000000b -128
sar dl ,3 ;dl = 11110000b -16
符号扩展AX至EAX: 先左移EAX16位,然后再算术右移EAX16位;
mov ax ,-128 ;EAX = ????FF80h
shl eax ,16 ;EAX = FF800000h
sar eax ,16 ;EAX = FFFFFF80h
ROL指令在向左一位后,把最高位同时复制到进位标志和最低位中,其指令格式与SHL指令相同:
循环右移,不解释了。
RCL指令在每位左移一位后,把进位标志复制到最低有效位中,把最低有效位复制到进位标志中。
如果把进位标志想象成一个填充到数字末尾的额外位的话,RCL指令就变成了一条简单的循环左移指令。在下例中,CLC指令清楚了进位标志,第一条RCL指令把BL的最高位送至进位标志,然后把其他位左移一位,第二条RCL指令把进位标志移入最低位,并把其他所有位左移:
clc ;CF = 0
mov bl ,88h ;CF,BL = 0 ,10001000b
rcl bl ,1 ;CF,BL =1,00010000b
rcl bl,1 ;CF,BL =0,00100001b
从进位标志中恢复一个位:RCL指令可以回复以前送入进位标志中的数据位。下面的例子把testval的最低位送入进位标志已进行检查,如果testval最低位是1,则发生跳转,如果最低位是0,RCL指令把数字回复成原值:
.data
testval BYTE 01101010b
.code
shr testval ,1
jc exit
rcl testval ,1
RCR一样,只不过是右移 就不说了。
在使用移位和循环移位指令对一个有符号整数移位一位后得到的值如果超出了该操作数表示的有符号的范围,那么溢出标志就会置位。换句话说,在进行移位操作后数字的符号位变反时,溢出标志置位。
mov al ,+127 ;AL = 01111111b
rol al ,1 ;OF = 1 ,AL = 11111110b
如果移位或循环移位的移位位数大于1,溢出标志值无定义。
SHLD和SHRD指令是从Intel386处理器开始引入的。SHLD指令把目的操作数左移指定的位数,左移出来的位用源操作数的高位来填充。指定对源操作数没有任何影响,但是符号标志、零标志、辅助进位标志。奇偶标志和进位标志都受影响。
SHLD 目的才作数,源操作数,移位位数