Although the jmp
instruction provides transfer of control, it is inconvenient to use when making decisions such as those you'll need to implement statements like if
and while
. The 80x86's conditional jump instructions handle this task.
The conditional jumps test one or more CPU flags to see if they match some particular pattern. If the flag settings match the condition, the conditional jump instruction transfers control to the target location. If the match fails, the CPU ignores the conditional jump and execution continues with the instruction following the conditional jump. Some conditional jump instructions simply test the setting of the sign, carry, overflow, and zero flags. For example, after the execution of a shl
instruction, you could test the carry flag to determine if the shl
shifted a 1 out of the H.O. bit of its operand. Likewise, you could test the zero flag after a test
instruction to check if the result was 0. Most of the time, however, you will probably execute a conditional jump after a cmp
instruction. The cmp
instruction sets the flags so that you can test for less than, greater than, equality, and so on.
The conditional jmp
instructions take the following form:
jcc label
;
The cc
in j
cc
indicates that you must substitute some character sequence that specifies the type of condition to test. These are the same characters the set
cc
instruction uses. For example, js
stands for jump if the sign flag is set. A typical js
instruction is:
js ValueIsNegative;
In this example, the js
instruction transfers control to the ValueIsNegative
label if the sign flag is currently set; control falls through to the next instruction following the js
instruction if the sign flag is clear.
Unlike the unconditional jmp
instruction, the conditional jump instructions do not provide an indirect form. They only allow a branch to a statement label in your program.
Intel's documentation defines various synonyms or instruction aliases for many conditional jump instructions.
Table 7-1, Table 7-2, and Table 7-3 list all the aliases for a particular instruction. These tables also list the opposite branches. You'll soon see the purpose of the opposite branches.
Table 7-1. j
cc
Instructions That Test Flags
Instruction | Description | Condition | Aliases | Opposite |
---|---|---|---|---|
| Jump if carry | Carry = 1 | ||
| Jump if no carry | Carry = 0 |
| |
Jump if zero | Zero = 1 | |||
| Jump if not zero | Zero = 0 |
| |
| Jump if sign | Sign = 1 | ||
| Jump if no sign | Sign = 0 |
| |
Jump if overflow | Overflow = 1 | |||
| Jump if no overflow | Overflow = 0 |
| |
Jump if parity | Parity = 1 | |||
| Jump if parity even | Parity = 1 |
| |
| Jump if no parity | Parity = 0 |
|
|
| Jump if parity odd | Parity = 0 |
|
|
Table 7-2. j
cc
Instructions for Unsigned Comparisons
Description | Condition | Aliases | Opposite | |
---|---|---|---|---|
| Jump if above ( | Carry = 0, Zero = 0 |
|
|
| Jump if not below or equal ( | Carry = 0, Zero = 0 |
|
|
| Jump if above or equal ( | Carry = 0 |
|
|
| Jump if not below ( | Carry = 0 |
|
|
| Jump if below ( | Carry = 1 |
|
|
| Jump if not above or equal ( | Carry = 1 |
|
|
| Jump if below or equal ( | Carry = 1 or Zero = 1 |
|
|
| Jump if not above ( | Carry = 1 or Zero = 1 |
|
|
| Jump if equal ( | Zero = 1 |
|
|
| Jump if not equal ( | Zero = 0 |
|
|
Table 7-3. j
cc
Instructions for Signed Comparisons
Instruction | Description | Condition | Aliases | Opposite |
---|---|---|---|---|
| Jump if greater ( | Sign = Overflow or Zero = 0 |
|
|
| Jump if not less than or equal ( | Sign = Overflow or Zero = 0 |
|
|
| Jump if greater than or equal ( | Sign = Overflow |
|
|
| Jump if not less than ( | Sign = Overflow |
|
|
| Jump if less than ( | Sign <> Overflow |
|
|
| Jump if not greater or equal ( | Sign <> Overflow |
|
|
| Jump if less than or equal ( | Sign <> Overflow or Zero = 1 |
|
|
| Jump if not greater than ( | Sign <> Overflow or Zero = 1 |
|
|
| Jump if equal ( | Zero = 1 |
|
|
| Jump if not equal ( | Zero = 0 |
|
|
One brief comment about the Opposite column is in order. In many instances you will need to be able to generate the opposite of a specific branch instruction (examples appear later in this section). With only two exceptions, a very simple rule completely describes how to generate an opposite branch:
If the second letter of the jcc
instruction is not an n, insert an n
after the j
. For example, je
becomes jne
and jl
becomes jnl
.
If the second letter of the j
cc
instruction is an n
, then remove that n
from the instruction. For example, jng
becomes jg
and jne
becomes je
.
The two exceptions to this rule are jpe
( jump if parity is even) and jpo
(jump if parity is odd). These exceptions cause few problems because (1) you'll hardly ever need to test the parity flag, and (2) you can use the aliases jp
and jnp
as synonyms for jpe
and jpo
. The "N/No N" rule applies to jp
and jnp
.
Though you know that jge
is the opposite of jl
, get in the habit of using jnl
rather than jge
as the opposite jump instruction for jl
. It's too easy in an important situation to start thinking "greater is the opposite of less" and substitute jg
instead. You can avoid this confusion by always using the "N/No N" rule.
The 80x86 conditional jump instructions give you the ability to split program flow into one of two paths depending on some condition. Suppose you want to increment the AX register if BX is equal to CX. You can accomplish this with the following code:
cmp( bx, cx ); jne SkipStmts; inc( ax ); SkipStmts:
The trick is to use the opposite branch to skip over the instructions you want to execute if the condition is true. Always use the "opposite branch (N/No N)" rule given earlier to select the opposite branch.
You can also use the conditional jump instructions to synthesize loops. For example, the following code sequence reads a sequence of characters from the user and stores each character in successive elements of an array until the user presses the enter key (carriage return):
mov( 0, edi ); RdLnLoop: stdin.getc(); // Read a character into the al register. mov( al, Input[ edi ] ); // Store away the character. inc( edi ); // Move on to the next character. cmp( al, stdio.cr ); // See if the user pressed Enter. jne RdLnLoop;
Like the set
cc
instructions, the conditional jump instructions come in two basic categories: those that test specific processor flags (e.g., jz
, jc
, jno
) and those that test some condition (less than, greater than, etc.). When testing a condition, the conditional jump instructions almost always follow a cmp
instruction. The cmp
instruction sets the flags so that you can use a ja
, jae
, jb
, jbe
, je
, or jne
instruction to test for unsigned less than, less than or equal, equal, unequal, greater than, or greater than or equal. Simultaneously, the cmp
instruction sets the flags so that you can also do a signed comparison using the jl
, jle
, je
, jne
, jg
, and jge
instructions.
The conditional jump instructions only test the 80x86 flags; they do not affect any of them.