我想检查AL
的第0,3,6,7位是否全部 1 或不是TEST
指令。
我知道我可以用这段代码检查第0位:
TEST AL,1
但是如何一起检查0,3,6,7位?
答案 0 :(得分:2)
你的头衔正在向身体提出相反的问题。对于单个位,它几乎相同(test al,1<<bit_position
/ jz
或jnz
)。但是当你需要测试多个位时,它们确实是不同的问题。
要检查全零,它仍然很容易,因为当{AND}操作的结果为0时,test
设置ZF。所以屏蔽要查看的位在,并检查ZF。请注意,您可以jz
或jnz
,setz/nz al
或cmovz/nz ecx, edx
。
test al, mask
jz all_bits_selected_by_mask_were_zero
;; fall through path: at least one non-zero bit
要检查全部,通常的习惯用语为x & mask == mask
。这在asm中并不理想,特别是在立即数不变的情况下,因为and
和cmp
需要两次常量。另一种方法是反转所有位,然后使用前一种方式检查零。 (这为寄存器其他保存代码字节而不是AL,但对于op al, imm8
的大多数指令,都有特殊的2字节编码。
not al
test al, mask
jz all_bits_selected_by_mask_were_one
;; fall through path: at least one unset bit
;;; or if mask has only a single bit set:
test al, single_bit_mask
jnz the_bit_was_set
另一个优化:如果你需要测试EAX的第二个字节中的一些位,它会将代码字节保存为ah
,但是this adds a cycle of latency on Haswell/Skylake。
例如test eax, 3<<8
与test ah, 3
。
对于单个位,bt eax, 11
测试第11位(设置/清除CF,因此如果你想取这个位并将其添加到其他地方,你可以做一些像adc edx, 0
这样有趣的东西。)但{ {1}}无法与JCC进行宏观融合,因此bt
效率更高。
在任何一种情况下,面具都是test eax, imm32
。给定位置中由设置位表示的数字为1<<0 | 1<<3 | 1<<6 | 1<<7
,汇编程序常量以数字表示。
当然,您可以用二进制编写常量(例如,在NASM中使用1<<n
后缀),这样就可以 b
。