[音乐]
上两讲主要介绍了IA-32的传送指令,和定点算术运算指令,
本讲接着介绍按位操作指令,主要包括按位逻辑运算,
和移位运算指令,同样本讲所介绍的所有
细节内容不需要记忆。
IA-32常用指令类型当中,第三种是按位运算指令,
在按位运算指令当中,有按位逻辑操作,比如说按位取反,按位
相与,按位或,按位异或,按位测试, TEST这种指令它实际上是一种与操作,
测试的结果仅影响这个标志信息,显然这些按位操作,它也
可以对8位或者16位或者32位数据分别进行按位运算,
在这些逻辑运算指令当中, 仅取非指令,NOT指令不影响标志,
其它的这些指令标志信息当中的OF和CF标志总是等于0,
而ZF和SF则根据结果来设置,比如说按位与
与出来的结果如果是全0,那么ZF标志就等于1,
如果与出来的结果第一位是1,那么SF标志就是1, 当然或、
异或和测试TEST都是一样的。
下面我们来看一个例子, 假定在1000号单元开始的4个字节
当中,存放着是00000F89这样4个字节
在1004这个单元当中,存放着是00 001270H这样的4个字节
然后eax这个寄存器的内容是FF00 0001,ecx的内容是0000
1000,在这个前提条件下我们来看一下 以下的这些指令它们运行的这个结果是什么?
首先我们来看第一条指令,第一条指令是把ax的内容,也就是这个16位的操作数,
各位取反再放到ax里面,
显然ax里面的内容是eax的低16位,
eax则是32位的寄存器,低16位的内容就 是ax寄存器的内容,所以ax寄存器的内容就是
0001H,各位取反以后,十六进制的0就是十六进制的F,
1的话就是0001,它取反就是 1110,1110就是十六进制的E,
所以这条指令运行的结果就使得ax的内容 从0001H变成FFFEH。
下面这条指令是将一个组存单元里面的内容
而eax的寄存器的内容进行按位相与,
与出来的结果再写到这个组存单元中,这个组存单元的地址
是ecx里面的内容,就是1000H,也就是这个
32位和eax的内容,也就是这边的
32位按位相与以后,再把它修改到1000号单元里面去,
因此,我们可以看到这条指令的功能就是把 1000号单元里面的内容就是这边的这个
和eax里面的内容就是这个按位相与,我们可以看出前面的5位
前面的这个5位十六进制,因为这是全0,因此,
这个5位是全0,相与以后是全0,这两位是0,
那么和这个F8相与,这个两位十六进制也是0,因此,只剩这个9
和E相与,9的话是1001,E是0001,
然后按位与的结果应该是这一位是1,这边全是0, 十六进制的1就是它,因此最后的结果
是在这一个单元开始的4个字节 是这4个字节,然后下面这条指令
它的功能是把al里面的内容和
这一个存储器操作数进行按位或,或出来的结果再
放到al里面,因此,最终al里面的内容是把al里面的原先的值
也就是eax的第8位01H,和这个地址
所指的这个存储单元的内容,这个地址是ecx
加4,所以这一个地址是1004H,
而1004H里面的内容就是这一个,
那么我们现在实际上是这条指令是一个字节,
因此,取的是最低的这个70H这个字节, 然后把70H和al里面的内容
按位相或,或出来的话,7和0相或,还是7,
1和0相或也是1,所以最后的结果是71H,
下面这条指令实际上是把一个内存单元的内容
和ax里面的十六位的内容
进行异或,结果写到内存单元去,那么这个内存单元
的地址是ecx加4,也就是1001
加4,就是1004,所以是把1004这个单元开始的
十六位数据,也就是1270,1270,
和ax的内容,ax的内容就是eax的低十六位,
这个0001,也就是这边的0001, 按位进行异或操作,它的结果就是
前面0和任何数进行异或,是等于那个数,
然后0和1异或是等于1,所以 最后异或出来的结果是1271H,
然后这个是在这个地址开始的 两个字节当中,因为它是十六位的w
我们来看最后一个指令,这个是一个测试指令,
TEST指令,TEST指令它不改变任何寄存器
和存储单元的内容,仅影响标志信息, 这个标志信息的影响我们前面讲过
这个标志信息OF跟CF总是等于0, 各位相与以后,如果结果是0的话,
那么ZF等于1,最高位是1的话,SF等于1,
所以我们来看这个例子,实际上是把
ecx的内容和eax的内容各位相与,
那么ecx的内容就是00001000,然后eax的内容就是它,
各位相与以后,我们可以看到这 一位相与以后,是等于0,这个是等于0,这个等于0,
这等于0,这等于0,这个等于0,这个等于0,这个等于0,因此,最后的这个相与的结果- 是全0,
最后相与的结果全0,因此,这个ZF 应该等于1,它写错了,ZF应该等于1,
因为结果是0, 这个0标志应该等于1,SF应该是等于0,
因为最高位是0,所以等于0,这个是这一条指令结果,
当然另外两个标志总是等于0,这刚才我们讲过,这条指令执行完了以后,
得到的是个标志信息是这样的,而其它的寄存器 的内容或者内存单元的内容不会发生任何改变,
这个是一个例子, 那么按位运算除了我们前面讲的按位
进行逻辑运算以外,还可以进行移位操作,这个移位操作
可以是逻辑移位操作,前面这条指令是逻辑左移指令,
后面是逻辑右移指令,可以是对一个字节移,或者是一个
十六位的数据,或者是对32位数据左移、 右移,
另外还可以进行算术左移或者算术 右移,这个地方就是用A来表示,
因为左移会扩大倍数,左移1位相当于乘2,左移2位是乘4,
所以左移的时候,可能会数值变大,使得无法表示,这个时候可能会发生溢出,
因此左移的时候要判溢出,而右移的时候是高位补符号,如果是算术移位的话,
当然前面这种逻辑左右移,是左移低位补0,右移高位补0,它是补
0,而这样是右移的时候,是高位补符,逻辑左移,算术左移是完全一样的,
但算术移位的时候,左移一位,移位前和移位后的符号,
发生变化了,那它就发生了溢出,OF标志就会是1, 否则OF标志是0,显然它也有
不同长度的操作数,因此有不同的指令, 还有一种是循环的左移、
右移, 如果是左移的话,最高位会移到最低位
上去,如果是右移的话,最低位会移到最高位上去, 另外还有带进位的循环
左移和右移,这时候会把这个进位标志 作为一部分进行循环移位,它也有不同的长度指令,
我们举个例子,循环带进位左移指令 首先是要带进位的,而且是左移指令。
L是表示左移, 并且是循环的,它的这个操作实际上就是把最高
位,如果是移位的话,把最高位移到这个 进位当中去,而进位移到最低位,
然后其它的位左移一位,这个就是 循环带进位的左移,那么其它的也是类似,是这样
子,右移的话也是,只是方向相反,其它的都是一样的。
[音乐] [音乐]