汇编语言中变量的访问位



在下面的代码中。如果我想访问变量的个别位并将其与1进行比较。像cmp ax,1和keep一样,bit的位置增加1来获得下一个位,这样我就可以计算在该变量中设置为1的位数。这可能吗?

。Data
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右移,其好处是当ax中没有更多的位可计数时,我们可以立即跳出循环。

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- jump if cx==0,而不是相反:jump if 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

最新更新