一条指令清除 PF(奇偶校验标志)——获取结果寄存器中的奇数位
在 x86 汇编中,是否可以在任何初始寄存器配置下使用一条且仅有一条指令清除奇偶校验标志?
这相当于使用任何设置标志的操作(明确排除 mov
)创建一个具有奇数位的结果寄存器。
相比之下,设置奇偶校验标志可以在一条指令中完成:
cmp bl, bl
并且有很多方法可以用两条指令清除奇偶校验标志:
and bl, 0
or bl, 1
但是,一条指令的方法仍然难以捉摸。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
试试这个:
注意:此
cmp
指令的第一个字节是 0x80,并且 0x80-0x7F = 0x01。Try this:
Note: This
cmp
instruction's first byte is 0x80, and 0x80-0x7F = 0x01.请参阅其他答案以了解技巧,例如使用内存内容或始终清除 PF 的较新指令,无论任何寄存器中的位模式如何。
在一条指令中可以清除 PF,但在不知道寄存器内容的情况下,从同一指令获取结果寄存器中的奇数位似乎是不可能的。 (
mov al, 1
当然可以只完成问题的后半部分而不影响 FLAGS)。这个答案的其余部分是仅考虑问题中提出的方式编写的:在寄存器上使用传统的 ALU 指令,根据结果的低字节的奇偶校验设置 PF。
当应用于寄存器的两个副本(如
或 al, al
)时,任何 PF 更改指令都不能无条件地产生奇奇偶校验结果。同样,当应用于寄存器和完全定义结果的常量时,没有任何算术命令会产生奇校验结果(例如and al, 0
或or al, ffh
)。至于第二个操作数是任何其他常量的命令,结果将取决于寄存器的初始值,我们无法控制它。如果我们知道执行环境的一些细节,就有可能使用已知地址处的内存内容。在实模式下的 PC 兼容机上,您可以依赖 BIOS 数据结构。在 MS-DOS 中,可执行文件头也是如此。在 Windows 中,TEB 为
FS:0
。See other answers for tricks like using memory contents, or newer instructions that always clear PF regardless of the bit-pattern in any registers.
Clearing PF is possible in one instruction, but getting an odd number of bits in a result register from the same instruction appears not to be, without known register contents to start with. (
mov al, 1
could of course do just the latter part of the question without affecting FLAGS).The rest of this answer was written considering only the way proposed in the question: using traditional ALU instructions on registers that set PF according to the parity of the low byte of the result.
None of the PF-changing instruction can unconditionally produce an odd-parity result when applied to two copies of a register (like
or al, al
). Likewise, none of the arithmetic commands produces an odd-parity result when applied to a register and a constant that completely defines the result (likeand al, 0
oror al, ffh
). As for commands where the second operand is any other constant, the result would depend on the initial value of the register, and we have no control over that.If we knew some details of the execution environment, it could be possible to use the contents of memory at a well-known address. On PC compatibles in real mode, you can rely on BIOS data structures. In MS-DOS, ditto for executable header. In Windows, there's the TEB as
FS:0
.如果我们能够超越 8086 本身并进入现代时代,那么最近的 x86 指令集确实包含许多无条件清除奇偶校验标志的指令,尽管它们为什么要这样做并不总是清楚。但是在英特尔手册中搜索
PF
并查找“cleared”、“set to 0”等字符串,会发现几个:kortest*
,ktest*
(AVX-512)popcnt
(ABM 或 SSE4.2)ptest
(SSE4.1)rdrand< /code>
,
rdseed
vtestp*
(AVX)所以
ptest xmm0, xmm0 和 popcnt eax, eax 可能是最广泛使用的。
ptest
的优点是它不会修改除FLAGS
之外的任何寄存器。fcomi
系列很接近,因为当比较结果为< 中的任何一个时,它们会清除 PF。 > =
,但如果结果是“无序的”,他们会设置它,如果 x87 寄存器包含 NaN,则可能会发生这种情况。(这表明清除奇偶校验标志不相当于在8位寄存器中获取奇数位,因为有一些指令可以在其他条件下清除它。)
我认为这些指令是什么共同点是它们以特定方式设置某些标志(CF、ZF),与通常的“根据结果”不同。它们没有特别需要对其他标志做任何事情,但是指定它们保持不变会为不单独重命名它们的处理器引入对这些标志的输入依赖性。这是高效乱序执行的一个问题。
某些指令通过指定其他标志“未定义”来处理此问题,但由于某种原因,这些指令的设计者决定将它们归零。
If we can go beyond the 8086 itself and into the modern era, more recent x86 instruction sets do contain a number of instructions that unconditionally clear the parity flag, though why they should do so is not always clear. But searching the Intel manuals for
PF
and looking for strings like "cleared", "set to 0", etc, turns up several:kortest*
,ktest*
(AVX-512)popcnt
(ABM or SSE4.2)ptest
(SSE4.1)rdrand
,rdseed
vtestp*
(AVX)So
ptest xmm0, xmm0
andpopcnt eax, eax
are probably the most widely available.ptest
has the advantage that it doesn't modify any registers other thanFLAGS
.The
fcomi
family is close, as they clear PF when the result of the comparison is any of< > =
, but they set it if the result is "unordered", which could happen if x87 registers contain NaN.(This shows that clearing the parity flag is not equivalent to getting an odd number of bits in an 8-bit register, as there are instructions which will clear it under other conditions.)
I think what these instructions have in common is that they set certain flags (CF, ZF) in specific ways, different from the usual "according to the result". They have no particular need to do anything with the others, but specifying that they remain unchanged would introduce an input dependency on those flags for processors that do not rename them separately. This is a problem for efficient out-of-order execution.
Some instructions handle this issue by specifying that the other flags are "undefined", but for some reason, the designers of these instructions decided to zero them instead.
我认为除了
mov
(我闻到了面试问题)之外,唯一的方法是找到(奇迹般地,诚然)一个满足TEST src, dst
的寄存器或寄存器对。请参阅此处了解如何/何时设置 PF。目前,我的脑海中还没有出现能够满足该条件的 x86 寄存器/寄存器对。
I think the only way to do it besides
mov
(I smell interview question) is to find (miraculously, admittedly) a register or register pair that will satisfyTEST src, dst
. See here how / when PF is set.At this moment, no such x86 register/register pair that could satisfy that condition spring to mind.