The jmp
( jump) instruction unconditionally transfers control to another point in the program. There are three forms of this instruction: a direct jump and two indirect jumps. These instructions take the following forms:
jmplabel
; jmp(reg32
); jmp(mem32
);
The first instruction is a direct jump above. For direct jumps you normally specify the target address using a statement label. The label appears either on the same line as an executable machine instruction or by itself on a line preceding an executable machine instruction. The direct jump is completely equivalent to a goto
statement in a high-level language.[105]
Here's an example:
<< statements >> jmp laterInPgm; . . . laterInPgm: << statements >>
The second form of the jmp
instruction given earlier—jmp(
reg32
);
—is a register indirect jump instruction. This instruction transfers control to the instruction whose address appears in the specified 32-bit general-purpose register. To use this form of the jmp
instruction, you must load a 32-bit register with the address of some machine instruction prior to the execution of the jmp
. You could use this instruction to implement a state machine by loading a register with the address of some label at various points throughout your program and then use a single indirect jump at a common point to transfer control to one of those labels. The short sample program in Example 7-3 demonstrates how you could use the jmp
in this manner.
Example 7-3. Using register-indirect jmp
instructions
program regIndJmp; #include( "stdlib.hhf" ); static i:int32; begin regIndJmp; // Read an integer from the user and set ebx to // denote the success or failure of the input. try stdout.put( "Enter an integer value between 1 and 10: " ); stdin.get( i ); mov( i, eax ); if( eax in 1..10 ) then mov( &GoodInput, ebx ); else mov( &valRange, ebx ); endif; exception( ex.ConversionError ) mov( &convError, ebx ); exception( ex.ValueOutOfRange ) mov( &valRange, ebx ); endtry; // Okay, transfer control to the appropriate // section of the program that deals with // the input. jmp( ebx ); valRange: stdout.put( "You entered a value outside the range 1..10" nl ); jmp Done; convError: stdout.put( "Your input contained illegal characters" nl ); jmp Done; GoodInput: stdout.put( "You entered the value ", i, nl ); Done: end regIndJmp;
The third form of the jmp
instruction given earlier is a memory-indirect jmp
. This form of the jmp
instruction fetches the double-word value from the memory location and jumps to that address. This is similar to the register-indirect jmp
except the address appears in a memory location rather than in a register. Example 7-4 demonstrates a rather trivial use of this form of the jmp
instruction.
Example 7-4. Using memory-indirect jmp
instructions
program memIndJmp; #include( "stdlib.hhf" ); static LabelPtr:dword := &stmtLabel; begin memIndJmp; stdout.put( "Before the JMP instruction" nl ); jmp( LabelPtr ); stdout.put( "This should not execute" nl ); stmtLabel: stdout.put( "After the LabelPtr label in the program" nl ); end memIndJmp;
Unlike the HLA high-level control structures, the low-level jmp
instructions can cause you a lot of trouble. In particular, if you do not initialize a register with the address of a valid instruction and you jump indirectly through that register, the results are undefined (though this will usually cause a general protection fault). Similarly, if you do not initialize a double-word variable with the address of a legal instruction, jumping indirectly through that memory location will probably crash your program.
[105] Unlike high-level languages, where your instructors usually forbid you to use goto
statements, you will find that the use of the jmp
instruction in assembly language is essential.