在汇编语言中访问变量的位

Accessing bit of a variable in assembly language

在下面的代码中。如果我想访问变量的单个位并将其与 1 进行比较。像 cmp ax,1 并保持将位的位置递增 1 以获得下一位,以便我可以计算该变量中设置为 1 的位数.这可能吗?

.数据
var dw 1234
.code

如果您的目标是 16 位或 32 位体系结构,则不是很清楚。

一位一位地计算位的典型方法如下:

mov cx, 1       // set mask bit
mov bx, 0       // initialise counter to accumulate bits
next_bit: 
test ax, cx     // check if the current bit is set, ZF==1 if not
jz skip_increment   // if ZF==1, do not increment
inc bx
skip_increment:
add cx, cx      // shift CX left by addition (8000h + 8000h will overflow to zero)
jnz next_bit   // if the mask did not yet overflow, continue loop

这个片段已经有很多优化:

  • 我们不需要计算1 << j,
  • 我们也不需要迭代计数 j
  • (0x8000 << 1) == 0 的溢出,在跳转到循环开始时检测到

如果我们愿意丢弃 ax,我们可以将 ax 右移,好处是当 [=16= 中没有更多位时,我们可以立即跳出循环] 来数。

mov cx, 0
next_bit: test ax, 1
jz skip_increment
inc cx
skip_increment:
shr ax, 1
jnz next_bit

我们可以做得更好吗?我们需要向前跳转以跳过增量,看起来效率不高。

xor cx, cx   // another way to clear the counter register
next_bit:
shr ax, 1    // shift out the LSB in ax to carry
adc cx, 0    // increment with carry
test ax, ax  // now we need to re-test ax for zero
jnz next_bit

奇怪的是 x86 指令集包含 jcxz - 如果 cx==0 则跳转,但不是相反:如果 cx != 0 则跳转。如果是这样,我们可以交换 ax 和 cx 的含义并且无需额外测试即可跳转到循环开头。

但我们仍然可以重新安排循环,这样我们就可以复制一些代码,使循环能够处理上一次和当前迭代中的元素。

sub cx, cx   // another way to clear cx, but also ensure CF==0
next_bit:
adc cx, 0    // add the carry from previous iteration
shr ax, 1    // move the LSB to carry, sets ZF, iff ax==0
jnz next_bit
adc cx, 0    // add the carry from last iteration