movsbl (%rax, %rcx, 1),%eax
and $0xf, %eax
我:
%rax=93824992274748
%eax=1431693628
%rcx=0
我真的不知道为什么我有这些结果:第一条指令是怎么得到%eax=97
的?为什么在二进制表示的97
和1111
之间的and
得到的是1
?
按位与运算比较两个操作数的位。在本例中,97 AND 15:
0110 0001 ;97
0000 1111 ;15
对于每一列位,如果列中的两位都为1,则该列的结果位为1。否则为0。
0110 0001 ;97
0000 1111 ;15
---------------
0000 0001 ;1
您可能想知道这是什么目的。实际上,你可以用AND做很多事情,其中很多第一眼看起来并不明显。将其中一个操作数视为数据,另一个操作数视为"过滤器",这很有帮助。
例如,假设我们有一个名为rand
的函数,每次调用它时都会在%eax
中返回一个随机的32位无符号整数。假设所有可能的值都是等可能的。现在,假设我们有一个叫做myEvent
的函数,我们是否调用它取决于rand
的结果。如果我们希望这个事件发生的几率是1/16,我们可以这样做:
call rand
and $0xf, %eax
jnz skip
call myEvent
skip:
之所以有效是因为16的每个倍数都有底部4位清除。所以这些是我们唯一感兴趣的位,我们可以使用and $0xf, %eax
忽略这4位左边的所有内容,因为它们在and
之后都会变成零。一旦我们完成了and
,我们就可以看到%eax
是否包含零。如果是,则%eax
在and
之前包含16的倍数。
下面是另一个例子。这告诉你%eax
是奇数还是偶数:
and $1, %eax
jnz isOdd
如果一个数字最右边的二进制数字是1,那么这个数字就是奇数。任何时候在高级语言中执行n % 2
,编译器都会将其替换为n & 1
,而不是执行实际的除法。