7.1.2 Conditional Jumps

The most common way to transfer control in assembly language is with a conditional jump. This is a two-step process: first test the condition, and then jump if the condition is true or continue if it is false.

Summary: The conditional jump instructions check flag status.

Conditional-jump instructions (except JCXZ) use the status of one or more flags as their condition. Thus, any statement that sets a flag under specified conditions can be the test statement. The most common test statements use the CMP or TEST instructions. The jump statement can be any one of 31 conditional-jump instructions. Conditional-jump instructions take a single operand containing the target address.

7.1.2.1 Jump Extending

In earlier versions of MASM, the NEAR and FAR operators cannot be used with conditional jumps on the 8086-80286 processors. MASM 6.0 automatically expands the jump instruction to include an unconditional jump to the destination, as long as a distance or size other than SHORT is specified or implicitly required from the operands. That is, MASM now generates the code that previously you had to write.

Conditional jumps cannot refer to labels more than 128 bytes away. Therefore, in versions of MASM prior to 6.0, they are often combined with unconditional jumps, which have no such limitation. For example, the following statement is valid as long as target is not far away:

; Jump to target less than 128 bytes away

jz target ; If previous operation resulted in

; zero, jump to target

However, once target becomes too distant, the following sequence is necessary to enable a longer jump. Note that this sequence is logically equivalent to the example above:

; Jumps to distant targets previously required two steps

jnz skip ; If previous operation result is

; NOT zero, jump to "skip"

jmp target ; Otherwise, jump to target

skip:

If the instruction is any of the conditional-jump instructions (except JCXZ and JECXZ ) and the target is greater than 128 bytes or is in a far segment, then jump-extending for an instruction such as je target generates two instructions to replace it:

1.The logical negation of the jump instruction, with a destination that skips over the second line it generates

2.An unconditional jump to the target destination

For example, if target is more than 128 bytes away, MASM generates these lines of code for je target:

jne $ + 2 + (length in bytes of the next instruction)

jmp NEAR PTR target

Now the conditional jump executes correctly.

The assembler generates this same code sequence if you specify the distance with NEAR PTR, FAR PTR, or SHORT. Therefore,

jz NEAR PTR target

becomes

jne $ + 5

jmp NEAR PTR target

even if target is nearby.

When skip is more than 128 bytes away, this example

mov ax, cx

jz skip ; Skip is more than 128 bytes away

.

. ; (additional code here)

.

skip:

generates code that looks like this:

7327:0000 8BC1 MOV AX,CX

7327:0002 7503 JNZ 0007

7327:0004 E9C000 JMP 00C7

7327:0007 (more code here)

MASM 6.0 enables this jump expansion feature by default, but you can turn it off with the NOLJMP form of the OPTION directive. See Section 1.3.2 for information about the OPTION directive.

If the assembler generates code to extend a conditional jump, it issues a level 3 warning saying that the conditional jump has been lengthened. You can set the warning level to 1 for development and to level 3 for a final optimizing pass to see if you can shorten jumps by reorganizing.

If you specify the distance for the jump and the target is out of range for that distance, a “Jump out of Range” error results.

Since the JCXZ and JECXZ instructions do not have logical negations, expansion of the jump instruction to handle targets with unspecified distances cannot be performed for those instructions. Therefore the distance must always be short.

The size and distance of the target operand determines the encoding for conditional or unconditional jumps to externals or targets in different segments. The new jump-extending and optimization features do not apply in this case.

NOTE:

Conditional jumps on the 80386 and 80486 processors can be to targets up to 32K bytes away, so jump extension occurs only for targets greater than that distance.

7.1.2.2 Jumps Based on Comparisons

The CMP instruction is specifically designed to test for conditional jumps. It does not change the destination operand—it compares two values without changing either of them. Instructions that change operands (such as SUB or AND) can also be used to test conditions.

Summary: SUB and CMP set the same flags.

Internally, the CMP instruction is the same as the SUB instruction, except that CMP does not change the destination operand. Both set flags according to the result that the subtraction generates.

Table 7.1 lists conditional-jump instructions for each comparison relationship and shows the flags that are tested to see if the relationship is true. Note the difference in instructions depending on the sign of the operands. Some of these are equivalent to instructions listed in the previous section.

Table 7.1 Conditional-Jump Instructions Used after Compare Instruction

Jump
Condition
Signed
Compare
Flags Tested
(Jump if True)
Unsigned
Compare
Flags Tested
(Jump if True)

= (Equal) JE ZF = 1 JE ZF = 1
<153> (Not equal) JNE ZF = 0, JNE ZF = 0  
> (Greater than) JG or JNLE ZF = 0 and SF = 0F JA or JNBE CF = 0 and ZF = 0
<= (Less than or equal to) JLE or JNG, ZF = 1 or SF <153> 0F JBE or JNA, CF = 1 or ZF = 1    
< (Less than) JL or JNGE, SF <153> 0F JB or JNAE, CF = 1    
>= (Greater than or equal to) JGE or JNL SF = 0F JAE or JNB, CF = 0  

In the CMP instruction, the mnemonic names always refer to the relationship of the first operand to the second operand. For instance, in this example JG tests whether the first operand is greater than the second.

cmp ax, bx ; Compares ax and bx

jg contin ; Equivalent to: If ( ax > bx ) goto

; contin

jl next ; Equivalent to: If ( ax < bx ) goto next

Several conditional instructions have two names. For example, JG and JNLE (Jump if Not Less or Equal) are equivalent. You can use whichever name seems more mnemonic in context.

7.1.2.3 Testing Bits and Jumping

Using CMP is not the only way to check a condition prior to a jump. You can also check the status of bits in the operands using the TEST instruction. This instruction tests for conditions prior to jumps by comparing specific bits rather than entire operands. Jump execution depends on whether certain bits are on or off.

Summary: Pairs of operands cannot be both registers or both memory locations.

The TEST instruction is the same as the AND instruction, except that TEST changes neither operand. If the result of the operation is 0, the zero flag is set, but the 0 is not actually written to the destination operand. The following example shows an application of TEST.

.DATA

bits BYTE ?

.CODE

.

.

.

; If bit 2 or bit 4 is set, then call task_a

; Assume "bits" is 0D3h 11010011

test bits, 10100y ; If 2 or 4 is set AND 00010100

jz skip1 ; --------

call task_a ; Then call task_a 00010000

skip1: ; Jump taken

.

.

.

; If bits 2 and 4 are clear, then call task_b

; Assume "bits" is 0E9h 11101001

test bits, 10100y ; If 2 and 4 are clear AND 00010100

jnz skip2 ; --------

call task_b ; Then call task_b 00000000

skip2: ; Jump taken

Generally, when you use TEST, one of the operands is a mask in which the bits to be tested are the only bits set. The other operand contains the value to be tested. If all the bits set in the mask are clear in the operand being tested, the zero flag is set. If any of the flags set in the mask are also set in the operand, the zero flag is cleared.

7.1.2.4 Jumping Based on Flag Status

Your code can jump based on the condition of flags rather than on the relationships of operands. Use the following conditional-jump instructions:

Instruction Jumps if

JO The overflow flag is set
JNO The overflow flag is clear
JC The carry flag is set (same as JB)
JNC The carry flag is clear (same as JAE)
JZ The zero flag is set (same as JE)
JNZ The zero flag is clear (same as JNE)
JS The sign flag is set
JNS The sign flag is clear
JP The parity flag is set
JNP The parity flag is clear
JPE Parity is even (parity flag set)
JPO Parity is odd (parity flag clear)
JCXZ CX is 0
JECXZ (80386/486 only) ECX is 0

The following example shows two ways to use the instructions from the list above:

; Uses JO to handle overflow condition

add ax, bx ; Add two values

jo overflow ; If value too large, adjust

; Uses JNZ to check for zero as the result of subtraction

sub ax, bx ; Subtract

jnz skip ; If the result is not zero, continue

call zhandler ; Else do special case

7.1.2.5 Anonymous Labels

Summary: Anonymous labels are alternatives to named labels.

Coding jumps in assembly language requires that you invent many label names. One alternative to continually thinking up new label names is using anonymous labels, which you can use anywhere in your program. But because anonymous labels do not provide meaningful names, they are best used for conditionally testing a few lines of code. You should mark major divisions of a program with actual named labels.

Use two at signs (@) followed by a colon (:) as an anonymous label. To jump to the nearest preceding anonymous label, use @B (back) in the jump instruction's operand field; to jump to the nearest following anonymous label, use @F (forward) in the operand field.

The jump in the example below uses an anonymous label:

; DX is 20, unless CX is less than -20, then make DX 30

mov dx, 20

cmp cx, -20

jge @F

mov dx, 30

@:

The items @B and @F always refer to the nearest occurrences of @:, so there is never any conflict between different anonymous labels.

7.1.2.6 Decision Directives

The high-level structures you can use for decision-making are the .IF, .ELSEIF, and .ELSE statements. These directives generate conditional jumps. The expression following the .IF directive is evaluated, and if true, the following instructions are executed until the next .ENDIF, .ELSE, or .ELSEIF directive is reached. The .ELSE statements execute if the expression is false. Using the .ELSEIF directive puts a new expression to be evaluated inside the alternative part of the original .IF statement. The syntax is

.IFcondition1
statements
[[.ELSEIFcondition2
statements]]
[[.ELSE
statements]]
.ENDIF

The decision structure

.IF cx = 20

mov dx, 20

.ELSE

mov dx, 30

.ENDIF

generates this code:

.IF cx == 20

0017 83 F9 14 * cmp cx, 014h

001A 75 05 * jne @C0001

001C BA 0014 mov dx, 20

.ELSE

001F EB 03 * jmp @C0003

0021 *@C0001:

0021 BA 001E mov dx, 30

.ENDIF

0024 *@C0003: