LowLevelControlStructs.pdf

(849 KB) Pobierz
AoA.book
Low Level Control Structures
Lo
w-Level Control Structures
Chapter Two
2.1
Chapter Overview
This chapter discusses “pure” assembly language control statements.
The last section of this chapter
discusses
hybrid
control structures that combine the features of HLA
s high le
v
el control statements with the
80x86 control instructions.
2.2
Low Level Control Structures
Until no
w
, most of the control structures you’
v
e seen and ha
v
e used in your programs ha
e been v
ery
similar to the control structures found in high le
v
el languages lik
e P
ascal, C++, and
Ada.
While these con
-
trol structures mak
e learning assembly language easy the
y are not true assembly language statements.
Instead, the HLA compiler translates these control structures into a sequence of “pure” machine instructions
that achie
v
e the same result as the high le
v
el control structures.
This te
xt uses the high le
el control struc
-
tures to a
v
oid your ha
ving to learn too much all at once. No
w
, ho
we
v
er
, it’
s time to put aside these high le
v
el
language control structures and learn ho
w to write your programs in
r
eal
assembly language, using lo
w-le
v
el
control structures.
2.3
Statement Labels
HLA lo
w le
v
el control structures mak
e e
xtensi
v
e use of
labels
within your code.
A lo
w le
v
el control
structure usually transfers control from one point in your program to another point in your program.
Y
ou
typically specify the destination of such a transfer using a statement label.
A statement label consists of a
v
alid (unique) HLA identifi
er and a colon, e.g.,
aLabel:
e procedure, variable, and constant identifiers, you should attempt to choose descriptive and
meaningful names for your labels. The identifier “aLabel” is hardly descriptive or meaningful.
Statement labels have one important attribute that differentiates them from most other identifiers in
HLA: you don’t have to declare a label before you use it. This is important, because low-level control struc-
tures must often transfer control to a label at some point later in the code, therefore the label may not be
defined at the point you reference it.
You can do three things with labels: transfer control to a label via a jump (goto) instruction, call a label
via the CALL instruction, and you can take the address of a label. There is very little else you can directly
do with a label (of course, there is very little else you would want to do with a label, so this is hardly a
restriction). The following program demonstrates two ways to take the address of a label in your program
and print out the address (using the LEA instruction and using the “&” address-of operator):
program labelDemo;
#include( “stdlib.hhf” );
begin labelDemo;
lbl1:
lea( ebx, lbl1 );
lea( eax, lbl2 );
stdout.put( “&lbl1=$”, ebx, “ &lbl2=”, eax, nl );
Beta Draft - Do not distribute
© 2001, By Randall Hyde
Page
751
v
v
Of course, lik
286680145.002.png
LowLevelControlStructs
lbl2:
end labelDemo;
Program 2.1
Displaying the Address of Statement Labels in a Program
HLA also allo
ws you to initialize dw
ord v
ariables with the addresses of statement labels. Ho
we
v
er
,
there are some restrictions on labels that appear in the initialization portions of v
ariable declarations.
The
most important restriction is that you must defi
ne the statement label at the same le
x le
v
el as the v
ariable
declaration.
That is, if you reference a statement label in the initialization section of a v
ariable declaration
appearing in the main program, the statement label must also be in the main program. Con
v
ersely
, if you
tak
e the address of a statement label in a local v
ariable declaration, that symbol must appear in the same pro
-
cedure as the local v
ariable.
The follo
wing program demonstrates the use of statement labels in v
ariable ini
-
tialization:
program labelArrays;
#include( “stdlib.hhf” );
static
labels:dword[2] := [ &lbl1, &lbl2 ];
procedure hasLabels;
static
stmtLbls: dword[2] := [ &label1, &label2 ];
begin hasLabels;
label1:
stdout.put
(
“stmtLbls[0]= $”, stmtLbls[0], nl,
“stmtLbls[1]= $”, stmtLbls[4], nl
);
label2:
end hasLabels;
begin labelArrays;
hasLabels();
lbl1:
stdout.put( “labels[0]= $”, labels[0], “ labels[1]=”, labels[4], nl );
lbl2:
end labelArrays;
Program 2.2
Initializing DWORD Variables with the Address of Statement Labels
Page
752
© 2001, By Randall Hyde
Version:
9/9/02
286680145.003.png
Low Level Control Structures
Once in a really great while, you’ll need to refer to a label that is not within the current procedure. The
need for this is sufficiently rare that this text will not describe all the details. However, you can look up the
details on HLA’s LABEL declaration section in the HLA documentation should the need to do this ever
arise.
2.4 Unconditional Transfer of Control (JMP)
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 one of the fol-
lowing three forms:
jmp label;
jmp( reg 32 );
jmp( mem 32 );
For the first (direct) jump above, you normally specify the target address using a statement label (see the
previous section for a discussion of statement labels). The statement label is usually on the same line as an
executable machine instruction or appears by itself on a line preceding an executable machine instruction.
The direct jump instruction is the most commonly used of these three forms. It is completely equivalent to a
GOTO statement in a high level language 1 . Example:
<< statements >>
jmp laterInPgm;
.
.
.
laterInPgm:
<< statements >>
The second form of the JMP instruction above, “jmp( reg 32 );”, is a register indirect jump instruction.
This instruction transfers control to the instruction whose address appears in the specified 32-bit general pur-
pose register. To use this form of the JMP instruction you must load the specified 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 (see “State Machines and Indirect Jumps” on page 784) by loading a register with the address
of some label at various points throughout your program; then, arriving along different paths, a point in the
program can determine what path it arrived upon by executing the indirect jump. The following short sam-
ple program demonstrates how you could use the JMP in this manner:
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 );
1. 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 absolutely essential.
Beta Draft - Do not distribute
© 2001, By Randall Hyde
Page 753
286680145.004.png
LowLevelControlStructs
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;
Program 2.3
Using Register Indirect JMP Instructions
The third form of the JMP instruction is a memory indirect JMP. This form of the JMP instruction
fetches a dword value from the specified memory location and transfers control to the instruction at the
address specified by the contents of the memory location. This is similar to the register indirect JMP except
the address appears in a memory location rather than in a register. The following program demonstrates a
rather trivial use of this form of the JMP instruction:
program memIndJmp;
#include( “stdlib.hhf” );
static
LabelPtr:dword := &stmtLabel;
Page 754
© 2001, By Randall Hyde
Version: 9/9/02
286680145.005.png
Low Level Control Structures
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;
Program 2.4
Using Memory Indirect JMP Instructions
Warning : unlike the HLA high level control structures, the low-level JMP instructions can get you into
a lot of trouble. In particular, if you do not initialize a register with the address of a valid instruction and you
jump indirect through that register, the results are undefined (though this will usually cause a general protec-
tion fault). Similarly, if you do not initialize a dword variable with the address of a legal instruction, jump-
ing indirect through that memory location will probably crash your program.
2.5 The Conditional Jump Instructions
Although the JMP instruction provides transfer of control, it does not allow you to make any serious
decisions. The 80x86’s conditional jump instructions handle this task. The conditional jump instructions are
the basic tool for creating loops and other conditionally executable statements like the IF..ENDIF statement.
The conditional jumps test one or more flags in the flags register to see if they match some particular
pattern (just like the SET cc instructions). If the flag settings match the instruction control transfers to the tar-
get location. If the match fails, the CPU ignores the conditional jump and execution continues with the next
instruction. 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 one out of the H.O. bit of its operand. Likewise, you could test the zero flag after a TEST
instruction to see if any specified bits were one. Most of the time, however, you will probably execute a con-
ditional jump after a CMP instruction. The CMP instruction sets the flags so that you can test for less than,
greater than, equality, etc.
The conditional JMP instructions take the following form:
J cc label;
The “cc” in J cc indicates that you must substitute some character sequence that specifies the type of condi-
tion 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 looks like this
js ValueIsNegative;
In this example, the JS instruction transfers control to the ValueIsNegative statement 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. The only form they allow is a branch to a statement label in your program. Conditional jump instruc-
tions have a restriction that the target label must be within 32,768 bytes of the jump instruction. However,
since this generally corresponds to somewhere between 8,000 and 32,000 machine instructions, it is unlikely
you will ever encounter this restriction.
Beta Draft - Do not distribute
© 2001, By Randall Hyde
Page 755
286680145.001.png
Zgłoś jeśli naruszono regulamin