Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare a signed value and an unsigned value in x86 assembly

I am having trouble finding a way to compare a positive number and a negative number in x86 assembly code.

For example: when I compare -1 and 1 I always get -1 as greater. I know that it's because 2's complement format makes the -1 bigger than 1 in underlying binary.

But can anyone provide a snippet of x86 assembly to compare positive number with a negative one and get it mathematically correct? (e.g 1 > -1)

Thanks!

like image 857
Roy Li Avatar asked Dec 04 '14 01:12

Roy Li


People also ask

What is the difference between signed and unsigned value?

A signed integer is a 32-bit datum that encodes an integer in the range [-2147483648 to 2147483647]. An unsigned integer is a 32-bit datum that encodes a nonnegative integer in the range [0 to 4294967295].

Can we compare signed and unsigned int in C?

According to C language specification, the common part of the range of the corresponding signed and unsigned integer type shall have identical representation (implying, according to the footnote 31, "interchangeability as arguments to functions").

Is it suggested to compare signed and unsigned numbers in C++?

Sure, comparisons between signed and unsigned would be slower, but their result would be more correct in some sense. @Nawaz Your bottom line conclusion is incorrect, unfortunately: if the signed type can contain the unsigned type, the unsigned will be converted to the signed type and not the opposite.

What is signed and unsigned integer in assembly language?

Signed variables, such as signed integers will allow you to represent numbers both in the positive and negative ranges. Unsigned variables, such as unsigned integers, will only allow you to represent numbers in the positive.


2 Answers

You're probably using one of the unsigned variants like:

cmp  eax, ebx
jb   lesser

There are equivalents for checking signed numbers against each other, such as:

cmp  eax, ebx
jl   lesser

This link gives a good run down on the jump variations, including their signed-ness and the flags they check, partially copied here for self-containment:

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
like image 191
paxdiablo Avatar answered Jan 03 '23 17:01

paxdiablo


You can't directly compare two numbers that have different signs. Actually most software languages have that flow. C and C++ specifically mention that in their documentation and in most cases will generate a warning when you use a signed and an unsigned integer in the same expression which then can result in an unknown sign.

The only way is to first check whether the signed number is negative, if so then you know it is smaller. Then you can compare the two numbers as unsigned integers.

; is eax < ebx (eax signed, ebx unsigned)

cmp eax, $0
jl less

cmp eax, ebx
jc less

Side note: it is obviously possible to compare two numbers signed if their size is less than the maximum size supported by the processor. In that case you extend the bits of the signed and unsigned appropriately, then you can compare as if both values were signed.

Assuming you wanted to compare two bytes al and bl, then you could have something like this:

movsx ax, al
xor bh, bh    ; or movzx bx, bl
cmp ax, bx
jl less

(Note, I do not guarantee that jl is correct, it may be jle or jnl...)

like image 30
Alexis Wilke Avatar answered Jan 03 '23 17:01

Alexis Wilke