What The Comparison Flags Mean, and How to Use Them
CS 301 Lecture, Dr. Lawlor
OK, so you want to know how some number A relates to some other number B. So you subtract them.
If A-B = 0, then A=B.
If A-B > 0, then A > B.
If A-B < 0, then A < B.
Yup, so "cmp eax,10" actually internally subtracts 10 from the value in
eax. If the difference is zero, the CPU sets flag ZF (the Zero
Flag). If the difference is positive or negative, the CPU sets
some other hideous flags to indicate this (the CPU sets various flags
for both the signed and unsigned comparisons).
Turns out, "sub eax,10" actually sets all the same flags. So you can compare two numbers with "cmp A,B" or "sub A,B", and you'll get the same result (but they're not totally interchangeable: "cmp" won't change A!).
So then, you want to jump if the previous comparison came out equal. You use the "je" instruction (Jump if Equal).
Or you want to jump if the previous subtraction came out zero. You use the "jz" instruction (Jump if Zero).
Turns out, "je" and "jz" are the same machine language instruction, because they both do entirely the same thing.
The bottom line is to do comparisons in assembly, you first do either a cmp or sub instruction, and then:
English
|
Less Than
|
Less or Equal
|
Equal
|
Greater or Equal
|
Greater Than
|
Not Equal
|
C/C++
|
<
|
<=
|
==
|
>=
|
>
|
!=
|
Assembly
(signed)
|
jl
|
jle
|
je or jz
|
jg
|
jge
|
jne or jnz
|
Assembly
(unsigned)
|
jb
|
jbe
|
je or jz
|
ja
|
jae
|
jne or jnz
|
The "b" in the unsigned comparison instructions stands for "below", and the "a" for "above".
In C/C++, the compiler can tell whether you want a signed and unsigned
comparison based on the variable's types. There aren't any types
in assembly, so it's up to you to pick the right instruction!
Examples
Subtract sets all the same comparison flags as "cmp". So this code returns 1, because 5 < 7.
mov ecx,5
sub ecx,7
jl yes_it_jumped
; ... else no, it didn't jump: return 0
mov eax,0
ret
yes_it_jumped: ; ... so return 1
mov eax,1
ret
(executable NetRun link)
Subtract also sets the zero flag, so here's a very small downward-counting loop:
mov edx,5
mov eax,0
loop_start:
add eax,7
sub edx,1
jnz loop_start ; Jumps if edx is still nonzero
ret
(executable NetRun link)