在汇编语言中访问变量的位
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
在下面的代码中。如果我想访问变量的单个位并将其与 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