汇编之位操作指令


前言

位运算的特点是运算单元是位,一个位的变化不会对旁边位产生影响。

逻辑运算指令

逻辑运算指令是位运算指令的子集,逻辑运算指的就是位运算指令中的与或非
ALU是算术逻辑单元,之前我们已经写了汇编之算术运算指令这篇博文,已经研究了“运算”,现在我们来研究“逻辑”。所谓的硬件控制,其实也就是控制这几个逻辑运算指令。

逻辑运算指令的通用格式是

AND/OR/XOR/TEST mem/reg,mem/reg/imm

(imm表示立即数寻址)

逻辑运算指令都是按位进行操作的,其中
NOT指令执行后不影响任何标志位,其他指令执行后,标志位CF和OF一定是0;而SF、ZF和PF位则根据运算结果设置;AF位无定义。
换句话说,5个逻辑运算指令中只有NOT不影响标志位

AND

汇编之位操作指令
常用于截取或屏蔽若干位二进制数
屏蔽——强行置0
如果要将一个数的第0,3,5位置零,只需要把这个数和1101 0110做AND即可

OR

汇编之位操作指令
可用于组合成某个字,或将某位置置1

XOR

汇编之位操作指令
同一个单元进行异或,相当于对单元清零

AND、OR和XOR

都是将结果回送给原操作数

TEST

汇编之位操作指令
TEST和AND的区别就是TEST的结果不回送,根据结果设置标志位
想想

SUB-CMP
AND-TEST

是不是挺类似的?可以类比记忆

TEST常用于判断操作数的某位或某几位是“0”还是“1”
看一个例子

TEST AL,01H
TEST AL,80H

第一句,TEST AL,01H
可以用于判断最低位是否为0
如果最低位是0,那么结果全0,这时可以用零标志位ZF判断,如果ZF=1,说明结果等于0,也就是说AL的最低位是0
如果最低位是1,那么结果是0000 0001,这是零标志位ZF=0,我们看到零标志位ZF=0,就能知道AL的最低位是1
根据最低位的0或1,可判断这个数的奇偶性,所以TEST也有判断奇偶的功能。
第二句,TEST AL,80H
可以用来判断最高位是否为0

类似的,TEST AL,0110 0000可以用来判断第5,6位是不是都是0
如果要你判断1,2,3,5,7位是否都为1,那要怎么做呢?
判断是否都为0是很简单的,直接TEST AL,1010 1110
如果运算结束后ZF=0,那么就说明这些位置全都为0
但是如果要判断都为1,那就比较麻烦,得一个一个判断,先TEST AL,0000 0010,再……
还有一种方法是先取反,然后就变成了判断这些位是否都为0,就比较简单了。

总之,TEST是进行与运算,结果不回送,但根据结果设置标志位。所以可以使用TEST指令,通过观察标志位,判断操作位的某位或某几位是0还是1。

NOT

汇编之位操作指令
汇编之位操作指令
NOT不同于与或异或,它是单操作数指令。
NOT就是求反,可以与NEG对比一下,他俩有点点像,但更多的是不同,NEG是求补指令,只针对负数。

逻辑运算指令应用实例

汇编之位操作指令
汇编之位操作指令

MOV AL,1011 1111
AND AL,1111 1100
结果是1011 1100
汇编之位操作指令
汇编之位操作指令
MOV AL,0100 0011
OR AL,0010 0000
结果是0110 0011
这两句的作用是把AL的第五位置1
汇编之位操作指令
汇编之位操作指令
MOV AL,0100 0000
TEST AL,1010 1111
结果是全0,说明0,1,2,3,5,7位全部为0
(其实我觉得PPT第一条语句里的040H没必要写成040H,写成40H就行了,它又不是字母开头的,不知道为什么要在前面加0)
汇编之位操作指令
整个前三条语句是看DL中的第二位是否为1
但是其实想看DL中的第二位是否为1,直接把DL和0000 0100相TEST就行了,这里的NOT对于判断第二位没什么用,可能加在这是为了迷惑你吧。
TEST的下一步常常是跳转指令,跳转条件是标识位。
第四句,jz exit,是跳到exit的意思
注意汇编中exit不是什么特殊的!exit就是一个自定义的标号。

注意PPT里的是汇编语句,汇编语句中用二进制是需要加B的
汇编之位操作指令
寄存器AX清零
汇编之位操作指令
测试两个数是否相等,也就是AX和0100 0010是否相等,相等的话跳转到MATCH

移位指令

移位指令统一的格式:

SAL/SHR/SAR/ROL/ROR/RCL/RCR/SHL reg/mem,1/CL

移位次数可以是1或者CL寄存器的值:为1时二进制数各个数位只移动移位;如果需要移位的次数大于1,必须将移位次数送CL寄存器,再执行移位指令。

设OPR为操作数,OPR可以是mem和reg
移位次数记为CNT
汇编之位操作指令
CNT大于一时,要先把CNT存在CL中,再执行SHL OPR,CL

条件标志位:
汇编之位操作指令
OF的值的解释有点不清楚,目前来看意思是:最后一次移位后的符号位与最后一次的前一次移位后的符号位不同,OF=1。也就是说,最后一次移位有没有使最高有效位(或者叫符号位)发生变化,如果变化了,那OF就等于1;如果没有变化,那么OF=1.

汇编之位操作指令
再提醒一下,计算机中存的都是补码。
没有强调是有/无符号数时,用算数或逻辑移动都行。

逻辑左移指令SHL和算术左移指令SAL

汇编之位操作指令

SHL SAL
L表示左移
H表示逻辑
A表示算数
当目的操作数为无符号数时,采用逻辑左移指令SHL;当目的操作数为有符号数时,采用算术左移指令SAL
算术左移和逻辑左移的规则是完全一样的,就是都在右边添0,相当于原数乘2。
算术左移,可能你会觉得有点奇怪,可以参考这个有效的左移
总之,算术左移和逻辑左移,基本就是一样的,而且都是可以实现乘2的功能,这个是确定的,你记着就行(也可以看上面的网址理解一下)

逻辑右移指令SHR和算术右移指令SAR

汇编之位操作指令
注意右移并不等同于除2,右移是比较复杂的,咱们在这里先不研究。
无符号数的右移就是补0
有符号数分为正数和负数
正数:右移左边补0
负数:右移左边补1
总之就是补符号位的数。

逻辑移位

逻辑移位无论左移右移都补0

左移和右移

算术左移和算术右移主要用来进行有符号数的倍增、减半;
逻辑左移和逻辑右移主要用来进行无符号数的倍增、减半。

带符号数的移位总是会让人有点迷茫,先记住这两句就行,这两句没错。

循环移位指令

循环移位可以用来做流水小灯

循环左移指令ROL和循环右移指令ROR

汇编之位操作指令
循环不带CF,循环的是目的操作数,只是移出的位在CF里也存一份

带CF位的循环左移指令RCL和循环右移指令RCR

汇编之位操作指令
带着CF一起循环
请注意带不带CF循环的区别。

移位指令实例

汇编之位操作指令
SAR:算术右移
把DI中的数据指向的内存单元中的一个字取出来,右移五次
汇编之位操作指令
DS:SI
DS是数据段寄存器
SI表示操作数的偏移地址
0F800→0F8000
因此真正的地址是0F8000+180A=0F980A
将0F980A中的内容取出,值为0064H
即0000 0000 0110 0100
算数右移,说明应该把他当成有符号数,符号位为0,移位补充的应该和符号位保持一致。右移五次后结果应该是0000 0000 0000 0011
也就是0003H
相当于100/32,余数不要,结果是3

汇编之位操作指令

SI=1450H=0001 0100 0101 0000
逻辑左移2位,结果为
0101 0001 0100 0000
即5140H
移位运算一定要化成二进制再移!看16进制你是看不出来的!

汇编之位操作指令
AX中的内容循环左移8次(就还是原来的内容)
再把AX和BX中的内容相或
(我觉得我还是没明白这个程序的意思)
AX中是0001 1000
循环左移八次

如果要求CX*9
可以

MOV AX,CX
MOV BX,CX
MOV CL,3
SAL AX,CL
ADD AX,BX

原理就是先乘8,再加1
那就等于乘9了
如果要求CX*8

MOV AX,CX
MOV CL,3
SAL AX,CL

当然你也可以一次一次的移动,

SAL AX,1

把这条语句重复8次。
注意SAL是算数左移,用来做有符号数的倍增
当然题里没明确是是有符号数,其实用两种都可以