在x86汇编语言中,是否可以获取寄存器的第一位?我想获取eax
寄存器的第一位并将其移至ebx
,但我还不确定如何执行此操作。
.stack 2048
.data
ExitProcess proto, exitcode:dword
.code
start:
mov eax, 3;
;now I want to move the first bit of eax into ebx. How can I obtain the first bit from eax?
invoke ExitProcess, 0
end start
答案 0 :(得分:12)
如果通过“第一位”表示最低有效位,则尝试:
...
mov ebx, eax
and ebx, 01
您显然不明白指令会立即对所有指定寄存器中的位进行操作,而“和”指令会逐位组合它们的操作数。
下面的工作也是如此,可以说是对你的请求的更直接的解释(“获取eax的第一位,然后放入EBX”)但它会破坏EAX的内容:
...
and eax, 1
mov ebx, eax
在汇编代码中,由于寄存器很少,它们的内容往往很珍贵,因此通常可以避免在计算新结果时破坏一个寄存器的内容。 (当你不能,你不能,但这种情况很容易避免)。
最后,你可以写:
...
mov ebx, 1
and ebx, eax
这很好用,和其他两个一样快。我更喜欢第一个,因为它强调恕我直言,因为首先提到它,而不是“1”,这只是一个偶然的常数,我关心的价值(EAX的内容)。这种风格似乎并不重要,但是如果你编写了大量的代码,特别是这些神秘的东西,比如汇编程序,为了最大限度地提高后续可读性,它是值得的。
找到英特尔参考手册并仔细阅读以了解每台机器指令的作用是值得的。这似乎是一项艰巨的任务,因为它是一本大书;只关注你最初似乎需要的说明。
答案 1 :(得分:5)
从寄存器中获取一个位涉及and
操作,其掩码在感兴趣的位位置为1,在所有其他位中为0。然后,可选择rotate right
或rotate left
将该位移动到结果中的所需位置。
答案 2 :(得分:0)
您还可以使用汇编的旋转属性,即使用位指令将指定位复制到进位标志中,我们可以使用rotation-carry标志指令。
我认为这对于理解在使用和放置爆破位的位置和方式方面的进展非常有效。
答案 3 :(得分:0)
如上所述,在这里使用mov
和and
是最快的解决方案,但是编程的有趣之处在于,可以为一个问题找到很多解决方案,因此,作为效率较低的 alternative ,您可以使用以下代码之一。
所以您也可以像这样解决它:
xor ebx, ebx ; sets ebx = 0
TEST eax, 1 ; is the lowest bit set?
JZ skip_add ; if low bit is zero, skip next instruction
; if lowest bit was set / AND op resulted not zero
add ebx, 1 ; ebx += 1, or use `INC ebx`
skip_add:
; process the result
或者,您也可以使用:
xor ebx, ebx ; ebx = 0
shr eax, 1 ; shift right: lowest bit in carry flag now
adc ebx, 0 ; ebx += 0 + carry bit
shl eax, 1 ; get back original value of eax, `shl` and `or` with ebx
or eax, ebx ; or use `push eax` and `pop eax` instead
另一个选择(与其他答案类似,但更昂贵):
push eax
and eax, 1
xchg ebx, eax ; swap contents, could also use `mov` here
pop eax
请注意,两种解决方案都不会更改eax
中的值,因此您仍然可以自由使用eax中的值。还要注意,注释的值是eax
的值为3,因为在问题中使用了mov eax, 3
。
如果您已经知道ebx
为零,则可以跳过xor
行,如果更改eax
没关系,则可以删除shl
操作也是如此。如您所见,实际操作大约由两条指令完成。关于µop,请参阅Peter的评论。
答案 4 :(得分:-2)
......第一位:
test eax, 1
setz ebx
德克