我在寻找一种比较x86汇编代码中正数和负数的方法。
例如:当我比较-1和1时,我总是得到-1比1更大的结果。我知道这是因为2的补码格式使得负数在底层二进制中比正数更大。
但是否有人可以提供一段x86汇编代码来正确地进行正负数比较(例如1>-1)?
你可能在使用以下其中一种未签名的变量,例如:
cmp eax, ebx
jb lesser
对于检查有符号数之间的等价物,例如:
cmp eax, ebx
jl lesser
这个链接提供了有关跳转变体的很好的概述,包括它们的符号和它们检查的标志,这里部分内容是复制的:
Instruction Jump if ... Signed? Flags
----------- ----------- -------- -----
JO overflow OF=1
JNO not overflow OF=0
JS sign SF=1
JNS not sign SF=0
JE/JZ equal
zero ZF=1
JNE/JNZ not-equal
not-zero ZF=0
JB/JNAE/JC below
not-above-or-equal
carry unsigned CF=1
JNB/JAE/JNC not-below
above-or-equal
no-carry unsigned CF=0
JBE/JNA below-or-equal
not-above unsigned CF=1 or ZF=1
JA/JNBE above
not-below-or-equal unsigned CF=0 and ZF=0
JL/JNGE less
not-greater-or-equal signed SF<>OF
JGE/JNL greater-or-equal
not-less signed SF=OF
JLE/JNG less-or-equal
not-greater signed ZF=1 or SF<>OF
JG/JNLE greater
not-less-or-equal signed ZF=0 and SF=OF
JP/JPE parity
parity-even PF=1
JNP/JPO not-parity
parity-odd PF=0
JCXZ/JECXZ CX register is zero
ECX register is zero
两个符号不同的数字不能直接进行比较。实际上大多数软件语言都有这个规则。C和C++在其文档中具体提到了这一点,并且在您在同一表达式中使用有符号和无符号整数时,通常会生成警告,这可能导致未知的符号。
唯一的方法是首先检查有符号数是否为负数,如果是,则知道它比另一个数字小。然后您可以将这两个数字作为无符号整数进行比较。
; is eax < ebx (eax signed, ebx unsigned)
cmp eax, $0
jl less
cmp eax, ebx
jc less
顺便提一下:如果两个数字的大小都小于处理器支持的最大大小,那么显然可以比较它们是否带符号。在这种情况下,您需要适当地扩展有符号和无符号位,然后就可以像两个有符号值一样进行比较。
假设您想要比较两个字节 al 和 bl,则可以使用以下代码:
movsx ax, al
xor bh, bh ; or movzx bx, bl
cmp ax, bx
jl less
movsx eax, al
/ movzx ebx, bl
是最有效的方法。(在现代x86的16位模式下也是如此,以避免错误依赖)。无论如何,除非您需要代码在pre-386上运行,否则在大多数CPU上,movzx bx, bl
比写BH然后读取BX更好。 - Peter Cordes
cmp(0xff, 0xff)
的操作,将相同的位模式解释为一个操作数的255,而另一个操作数的-1?这就是比较无符号和有符号值所意味的,也是Alexis的答案所回答的。Pax的答案涵盖了仅在两个2的补码数字之间进行有符号比较的情况,无论其是否为正数。 - Peter Cordes