我需要在 8086* 程序集中尽可能短(小于 10 个字节)编写以下 C 代码片段,但我只能设法将其写入 12 个字节。
有任何想法吗?
while (ax) {
bx--;
ax &= ax-1;
}
我需要在 8086* 程序集中尽可能短(小于 10 个字节)编写以下 C 代码片段,但我只能设法将其写入 12 个字节。
有任何想法吗?
while (ax) {
bx--;
ax &= ax-1;
}
您尝试的操作称为人口计数,即计算寄存器中设置的位数。
在较新的 CPU 中实际上只有一条指令。而且由于在 2018 年瞄准原始 8086 确实没有那么有趣。
简单的答案是:
f3 0f b8 c0 popcnt eax,eax
29 c3 sub ebx,eax
6 个字节,如果您愿意允许一个正值输入ebx
并且可以假设/确保 ebx 一开始就为零,则可以减少到 4 个字节。
请注意,没有必要使用 16 位寄存器,已经很多年没有了。
如果您希望代码在原始 8086(不支持popcnt
)上工作,则必须保留循环。
以下非常简单的代码占用 12 个字节:
85 c0 test ax,ax ;is AX zero?
74 08 je <done> ;yes, bail out
<loop>:
4b dec bx ;bx--
89 c1 mov cx,ax
49 dec cx ;cx = ax - 1
21 c8 and ax,cx ;ax = ax & (ax-1)
75 f8 jne <loop> ;repeat until done
<done>:
您可以通过以稍微低效的方式计算位来将其减少到 9 个字节。这里我们简单地测试一下 ax 的所有 16 位。
<loop>:
d1 e0 shl ax,1 ;MSb to carry flag (CF)
83 db 00 sbb bx,0 ;bx=bx-CF
85 c0 test ax,ax ;is AX zero?
75 f9 jnz <loop> ;if not then loop until done
诀窍是了解代码的作用,然后以不同的方式重新表述它。