Chapter 7 - Controlling Program
Chapter 7 - Controlling Program
CHAPTER 7
The fir st sec tion cove rs jumps from one point in the progr am to another. It explains how MASM 6.1
optimiz es both unconditional
and conditional jumps under c ertain cir cumstanc es, so that you do not have to spec ify every a ttribute.
The
instructions you cande
section also sctoribe
use tests conditional jumps.
The next se ction desc ribes loop structures that repeat actions or e valuate conditions. It discusses
M ASM directives,
.WHILE and .REPEAT,such a sthat generate appropriate compare, loop, and jump instructions for
you, anddirectives
.ELSEIF the that generate jump instructions.
The “Proc edures” se ction in this cha pter explains how to write an asse mbly-language pr oce
dure. It c overfors the
func tionality extended
PROC, a PROTO dire ctive that lets you write procedure prototypes similar to
those use d in C, an
directive that automa tes parameter passing, and options for the stack-frame setup inside procedures.
The last section e xplains how to pass progra m control to an interrupt routine.
Jumps a re the most direct way to cha nge program control from one location to anothe r. At the
pr ocessorthelevel,
changing jumps
va lue of the work by
IP (Instruction Pointer) register to a ta rget offset and, for far jumps, by c hanging the
CS register to a new
segment address. Jump instructions fall into only two categories: conditional and unconditional.
Unconditional Jumps
The JMP instruction transfers control unc onditionally to another instruction. JMP’s single operand
contains the addre ss of the
target instruction.
Unconditional jumps skip over code that should not be executed, as shown here:
The distance of the target from the jump instruc tion and the siz e of the ope rand de ter mine
the a ssemble
instruction. Ther’s enc oding
longer of the, the more byte s the a ssemble r uses to c ode the instruction. In ve rsions
the distance
of M ASM prior
unconditional to jumps
NEAR 6.0, sometimes ge nerated inefficient code, but MASM can now optimize unc onditional
jumps.
Jump Optimizing
The assembler determine s the smallest e ncoding possible for the direct unc onditional jump. M
ASM doe so
operator, s not
you redo
quire
not ahave
distance
to dete rmine the corr ect distance of the jump. If you spec ify a
dista nce, it ove rrides any assembler
optimization. If the specifie d distance falls short of the targe t addr ess, the a ssemble r ge nerates an e rror.
If the than
longer specified
the jumpdistance
requires, isthe assembler encodes the given distance and does not optimize it.
The assembler optimizes jumps when the following conditions are met:
You do not spec ify SHORT, NEAR, FAR, NEAR16, NEAR32, FAR16, FAR32, or PROC as the distance of the
target.
The ta rget of the jump is not external and is in the sa me segment as the jump instruction. If the targe t is in a diffe
inse
re nt thegment
same (but
group), it is treated as though it were external.
If these two conditions are met, MASM uses the instruc tion, distance, and size of the ope ra nd
to de ter mine
encoding for thehow to No
jump. optimiz
syntaxechanges
the are necessary.
Note
This information about jump optimizing also applies to conditional jumps on the 80386/486.
Indirect Operands
An indirect opera nd provides a pointer to the target addre ss, ra ther than the a ddress itse lf. A pointer
is a va riable
address. that c ontains
The processor an
distinguishes indirect (pointer) operands from direct (address) operands by the instruction’s
context.
You c an specify the pointer’s size with the WORD, DWORD, or FWORD attributes. Default sizes
are based segment
the default on size .
If the indirect operand is a register, the jump is always a NEAR16 jump for a 16-bit register, and NEAR32
In this ca se, your code must cle ar the ambiguity with the NEAR32 or FAR16 keywords. The following
example
TYPEDEF shows how toNEAR32
to define use and FAR16 pointer types.
NFP TYPEDEF PTR NEAR32
FFP TYPEDEF PTR FAR16
jmp NFP PTR [var] ; NEAR32 indirect jump
jmp FFP PTR [var] ; FAR16 indirect jump
You ca n use an unconditional jump as a form of conditional jump by spec ifying the address
in a register
operand. or indirect
Also, you can usememor y memory opera nds to construct jump ta bles that wor k like C swit ch
indirect
statements,
statements, orPascal
Basic ON GOTO, ON GOSUB, or SELECT CASE sta tements, as shown in the following e xample.
extended:
mov ah, 8h ; Get second key of extended key
int 21h
. ; Use another jump table
. ; for extended
keys .
jmp next
ctrla: . ; CONTROL-A code here
.
.
jmp next
ctrlb: . ; CONTROL-B code here
.
.
jmp next
.
.
next: . ; Continue
In this instance, the indirect memory operands point to addresses of routines for handling different keystrokes.
Conditional Jumps
The most common way to transfer control in assembly language is to use a conditional jump. This is a two-step
process:
1. First test the condition.
2. Then jump if the condition is true or continue if it is false.
All conditiona l jumps except two (JCXZ and JECXZ) use the processor flags for their criter ia. T
hus,
clearsa nya sta
flagtement
can that
serve sets
as ora test basis for a conditional jump. The jump state ment c an be
any one ofA 30
instructions. conditional- jump
c onditional-jump instruction ta kes a single ope ra nd conta ining the target a ddress. You cannot
use a pointer
a target as youvalue a s unconditional jumps.
can with
Instruction Jumps if
The last two jumps in the list, JPE (Jump if Parity Eve n) and JPO (Jump if Parity Odd), are
useful
programs.onlyThe
for prcommunications
ocessor sets the parity flag if an opera tion produces a result with an even number
of set bits. A communications
program can compare the fla g against the parity bit received through the serial port to test for transmission errors.
The conditional jumps in the preceding list ca n follow any instruction that changes the processor flags, as these
examples show:
; Use s JO to handle overflow condition
add ax, bx ; Add two values
jo overflow ; If value too large, adjust
; Use s JNZ to check for zero as the result of subtrac tion
sub ax, bx ; Subtract
mov cx, Count ; First, initialize CX
jnz skip ; If the result is not zero, continue
call zhandler ; Else do special case
As the sec ond example shows, the jump does not have to immediately follow the instruction that alters the
flags. Sincethe flags, it can appear between the SUB instruction and the dependent jump.
not change
Inte rnally, the CMP instruction is the same as the SUB instruction, except tha t CMP does not change the de
stina tionaccording
set flags operand. Both
to the result of the subtraction.
You can compare signe d or unsigned values, but you must c hoose the subsequent conditiona l jump to reflec t
the
For corr ec t valueJLtype.
example, (Jump if Less Than) and JB (Jump if Below) may seem conceptually similar,
but a failure
difference to understand
be tween them ca n the
result in program bugs. Table 7.1 shows the correct conditional jumps for
comparisons of signed and
unsigned values. The table shows the ze ro, carry, sign, a nd overflow flags as ZF, CF, SF, and OF, respe ctively.
JE ZF = 1 JE ZF = 1
JNE ZF = 0 JNE ZF = 0
JG/JNLE ZF = 0 and SF = OF JA/JNBE CF = 0 and ZF = 0
JLE/JNG ZF = 1 or SF OF JBE/JNA CF = 1 or ZF = 1
JL/JNGE SF OF JB/JNAE CF = 1
JGE/JNL SF = OF JAE/JNB CF = 0
The mnem onic names of jumps a lways refe r to the comparison of CMP’s first operand
( destination) with the sec ond oper and
(source). For instance, in this example, JG tests whether the first operand is greater than the second.
The TEST instruction is the same as the AND instruction, except that TEST changes neither
operand. The following
shows an application example
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 a nd 4 are clear AND 00010100
jnz skip2 ;
-------- call task_b ; Then call task_b 00000000
skip2: ; Jump taken
The source operand for TEST is often a mask in whic h the test bits are the only bits set. The destination
operand contains
to be tested. If athe value
ll the bits set in the mask ar e clear in the de stination operand, TEST sets the zero flag. If
any of the flags set in the tion operand, TEST c lea rs the zero flag.
mask are also set in the destina
The 80386/486 processors provide additional bit-te sting instructions. The BT (Bit Te st) serie s of
instructions copy a spe cified bit
from the destination ope rand to the carry flag. A JC or JNC c an then route program flow depending on the result.
For variations
the BT on see the Reference.
instruction,
or bx, bx ; Is BX = 0?
jz is_zero ; Jump if so
This code is functionally equivalent to:
cmp bx, 0 ; Is BX = 0?
je is_zero ; Jump if so
but produc es smaller a nd faster c ode, since it does not use an immediate number as an operand. The
sam
test aere
technique alsobit:
gister’s sign lets you
Jump Extending
Unlike a n unconditional jump, a conditional jump c annot reference a la bel more than 128 bytes a way. For
example,
statement isthe
validfollowing
as long as target is within a distance of 128 bytes:
MASM c an automa te jum p-extending for you. If you target a conditional jump to a labe l
farthe
rewriter s than 128 byte
the instruc tion swith
awaany,unconditional
MASM jump, which e nsures that the jump can reac h its ta rget. If ta rget
lies within
range, a 128-byte
the assembler encodes the instruction jz targe t as is. Otherwise, MASM generates two substitute instructions:
The assembler generates this same code sequence if you specify the distance with NEAR PTR, FAR PTR
MASM enables a utom atic jump expansion by defa ult, but you can turn it off with the NOLJMP form
of
Forthe
information about the OPTION directive, see page 24.
If the assembler generates code to e xtend a c onditiona l jump, it issues a level 3 warning saying that the
conditional
le ngthened. jump
You has
c anbe set
en the wa rning leve l to 1 for deve lopment a nd to level 3 for a final optimizing
pass
jumps to
bysee if you can shorten
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 instruc tions do not have logica l negations, expansion of the jump
instruction
unspecifiedtodistances
handlecannot
targets with
be performed for those instructions. Therefore, the distance must always be short.
The size and distance of the target opera nd determines the enc oding for conditional or unconditional jumps to
externals or targets in
different segments. The jump-extending and optimization features do not apply in this case.
Note
Conditional jumps on the 80386 and 80486 proc essors can be to targets up to 32K away, so jump e xtension
greater than for
occurs only that distance.
targe ts
Anonymous Labels
When you c ode jumps in assembly language , you m ust inve nt many labe l names. One alte rnative
to continually
la bel names isthinking
to use upanonymous
new labels, which you can use a nywhere in your program. But
beca use anonymous la bels do not
provide me aningful names, they are best use d for jumping over only a few lines of code. You
should
program mark majornamed
with actual divisions
labels. of a
Use two at signs (@@) followe d by a c olon ( :) as a n anonymous labe l. To jump to the ne arest pre ceding
anonymous
(back) in label, use instruction’s operand field; to jump to the nearest following anonymous label, use @F
the jump
field.
jge @F
.
.
.
@@:
The items @B and @F always refer to the nearest occ urrences of @@:, so there is neve r a ny conflict betwe en
different
labels. a nonymous
Decision Directives
The high-level structures you ca n use for dec ision-ma king are the .IF, .ELSEIF, a nd .ELSE state me nts. These
dire ctives lgenerate
conditiona jumps. The e xpression following the .IF direc tive is evaluated, and if true, the following
instructions are executed
the next .ENDIF, untilor .ELSEIF directive is reache d. The .ELSE stateme nts execute if the
.ELSE,
expression is false. puts
.ELSEIF directive Using the expression inside the alternative pa rt of the original .IF sta tement to be
a new
evaluated. The syntax is:
.IF condition1
statements
[[.ELSEIF condition2
statements]]
[[.ELSE
statements]]
.ENDIF
.IF cx ==
0017 83 F9 14
20 * cmp c x, 014h
001A 75 05 * jne @C0001
001C BA 0014 mov dx, 20
.ELS
001F EB 03
E * jmp @C0003
0021 *@C0001:
0021 BA 001E mov dx, 30
.ENDI
0024
F *@C0003:
Loops
Loops repeat an action until a termination condition is reached. This condition can be a counter
or thetion.
evalua result
MASMof 6.1
an offers
expression’s
many ways to set up loops in your programs. The following list compares MASM loop
structures:
Instructions Action
LOOP Automa tically decrements CX. When CX = 0, the loop ends. The top of the loop cannot
be gre ater tha n 128 bytes from the LOOP instruc tion. (This is true for a ll
instructions.)
LOOPE/LOOPZ, Loops while equa l or not e qual. Chec ks both CX and the state of the ze ro fla g.
LOOPNE/LOOPNZ ends LOOPZ whe n e ither CX=0 or the zero flag is clea r, whiche ver occurs first.
whe n
LOOPNZ e ither CX=0 or the zero fla g is set, whichever occ urs first. LOOPE a nd
LOOPZ
asse mble to the sam e machine instruction, as do LOOPNE and LOOPNZ
whic heve r mnemonic best fits the context of your loop. Set CX to a numbe r out of r ange
if you don’t want a count to control the loop.
JCXZ, JECXZ Branches to a label only if CX = 0 or ECX = 0. Unlike other conditional-
jump instruc tions, which c an jump to either a near or a short la bel unde r the 80386 or
JCXZ and JECXZ always jump to a short labe l.
80486,
Conditional jumps Acts only if certain conditions met. Necessary if several conditions must be te sted.
Se e “Conditional Jumps,” page 164.
If LoopCount is zero, CX decrements to -1 on the first pass. It then must dec re ment 65,535 mor e
times
JCXZ tobefore
avoidr eaching 0. Use a
this problem:
Loop-Generating Directives
The high-leve l contr ol structures generate loop struc ture s for you. The se directive s are similar to the while
Pa scal, and ca n make your assem bly programs easier to code and to read. The a ssembler generate s the
appropriate assembly
These dire ctives c ode.
are summarized as follows:
Directives Action
.WHILE ... .ENDW The sta tements between .WHILE condition a nd .ENDW e xecute while the
condition is true.
.REPEAT ... .UNTIL The loop exe cutes at le ast once and continues until the condition given
afte r .UNTIL is true. Generates conditional jumps.
.REPEAT ... .UNTILCXZ Compares label to an expression and generates appropriate loop instructions.
.BREAK End a .REPEAT or a .WHILE loop unconditionally.
.CONTINUE Jump unconditionally past any remaining code to bottom of loop.
These constructs work much as they do in a high-level language such as C or Pascal. Keep in mind the following
points:
These directives generate appropriate processor instructions. They are not ne w instructions.
They require proper use of signed and unsigned data declarations.
These directives cause a set of instruc tions to e xecute ba sed on the e valua tion of some
condition. This
expression that eva luates to a signed or unsigned value, an e xpression using the binary operators in C (&&
flag. For more information about expression opera tors, see page 178.
The e valuation of the condition re quires the a ssemble r to know if the operands in the condition ar
eexplicitly
signed that
or a unsigned. To state
na med memory location contains a signed integer, use the signed data a llocation directive s
SDWORD.
.WHILE Loops
As with while loops in C or Pascal, the test condition for .WHILE is checked before the state ments inside the
loop e xecute. isIf false,
test condition the the loop does not execute. While the condition is true, the statements inside the loop repeat.
Use the .ENDW directive to ma rk the end of the .WHILE loop. When the condition become s false,
program
the first execution
stateme nt begins at the .ENDW directive . The .WH ILE directive generate s appropriate c
following
ompare and
The syntax is: jump statements.
.WHILE condition
statements
.ENDW
For exa mple, this loop copies the contents of one buffer to another until a ‘$’ character (marking the end of the
string) is found:
.DATA
buf1 BYTE "This is a string",'$'
buf2 BYTE 100 DUP (?)
.CODE
sub bx, bx ; Zero out bx
.WHILE (buf1[bx] != '$')
mov al, buf1[bx] ; Get a chara cter
mov buf2[bx], al ; Move it to buffer 2
inc bx ; Count
forward.ENDW
.REPEAT Loops
MASM’s .REPEAT direc tive allows for loop c onstructions like the do loop of C and the
REPEAT looptheofcondition
executes until Pasca l. following
T he loopthe .UNTIL (or .UNTILCXZ) directive bec omes true . Since the
condition
end of theisloop,
chethe
cked at always
loop the executes at least once. The .REPEAT directive generates conditiona l jumps. The
syntax is:
.REPEAT
statements
.UNTIL condition
.REPEAT
statements
.UNTILCXZ [[condition]]
where condition can also be expr1 == expr2 or expr1 != expr2. When two conditions are use
d, expr2 a register, or (if expr1 is a register) a memory location.
expression,
For e xample, the following code fills a buffer with charac ters typed at the keyboard. T he
loop
(chara ends when
cter 13) the ENTER ke y
is pressed:
.DATA
buffer BYTE 100 DUP (0)
.CODE
sub bx, bx ; Zero out bx
.REPEAT
mov ah, 01h
int 21h ; Get a key
mov buffer[bx], al ; Put it in the buffer
inc bx ; Incre ment the count
.UNTIL (al == 13) ; Continue until al is 13
The .UNTIL dire ctive generates c onditional jumps, but the .UNTILCXZ directive generates a LOO P instruction, a s
shown by the
listing file code for these examples. In a listing file, assembler-generated code is prec eded by an asterisk.
.REPEAT
*@C0001:
inc ax
.UNTIL ax==6
* cmp ax, 006h
* jne @C0001
.REPEAT
*@C0003:
mov ax, 1
.UNTILCXZ
* loop @C0003
.REPEAT
*@C0004:
.UNTILCXZ [bx].field != 6
* cmp [bx].field, 006h
* loope @C0004
Note that .ENDIF is not used with the .IF forms of .BREAK and .CO NTINUE in this context. The .BREAK
directives work the same way as the br eak and continue instructions in C. Execution continues at
the instruction
.UNTIL, following
.UNTILCXZ, the
or .ENDW of the nearest enclosing loop.
Instead of ending the loop execution as .BREAK does, .CONTINUE ca uses loop execution to
jump directly
evalua tes to c the
the loop codeof the
ondition thatnearest enclosing loop.
The following loop accepts only the keys in the range ‘0’ to ‘9’ and terminates when you press ENTER.
If you assemble the preceding source code with the /Fl and /Sg c ommand-line options and then view the
results
you will in
see the listing file,
this code:
.WHILE
10017 *@C0001:
0017 B4 08 mov ah, 08h
0019 CD 21 int 21h
.BREAK .IF a l == 13
001B 3C 0D * cmp al, 00Dh
001D 74 10 * je @C0002
.CONTINUE .IF (al '0') || (al '9')
001F 3C 30 * cmp al, '0'
0021 72 F4 * jb @C0001
0023 3C 39 * c mp al, '9'
0025 77 F0 * ja @C0001
0027 8A D0 mov dl, al
0029 B4 02 mov ah, 02h
002B CD 21 int 21h
.END
0W02D EB E8 * jmp @C0001
002F *@C0002:
The high- leve l contr ol structures ca n be ne sted. Tha t is, .REPEAT or .WHILE loops c an contain .REPEAT
well as .IF statements.
If the c ode ge nerated by a .WHILE loop, .REPEAT loop, or .IF statement generates a conditional or unconditional
jump,
encodeMASM
s the jump using the jump extension a nd jump optimization techniques described in “ Unconditional
Jumps,” pageJumps,”
“Conditional 162, page
and 164.
Expression Operators
The binar y r elational operators in MASM 6.1 a re the sa me bina ry operators used in C. These operators
generate MASM compare,
test, and conditional jump instructions. High-level control instructions include:
Operator Meaning
== Equal
!= Not equal
> Greater than
>= Greater than or equal to
< Less than
<= Less than or equa l to
& Bit test
! Logical NOT
&& Logical AND
|| Logical OR
A c ondition without operators (other than !) tests for nonz ero as it does in C. For example, .WHILE (x) is the
same
!= 0), aand
s .WHILE
.WHILE(x(!x) is the sa me as .WHILE (x == 0).
You can a lso use the flag names (ZERO?, CARRY?, OVERFLOW?, SIGN?, and PARITY?) as opera nds in
conditions
high-level with the structures. For e xample , in .WHILE ( CARRY?), the value of the carry flag
control
determines
condition. the outc ome of the
You can use the PTR operator to tell the asse mbler that a particular operand in a re giste r or c onsta nt is a
signed number, as in these
examples:
Without the PTR operator, the assembler would treat the contents of BX as an unsigned value.
You can a lso spe cify the size attributes of operands in me mory locations with SBYTE, SWO RD, and
SDWORD
.WHILE, and .REPEAT.
.DATA
mem1 SBYTE ?
mem2 WORD ?
.IF mem1 > 0
.WHILE mem2 < bx
.WHILE SWORD PTR ax < count
Precedence Level
As with C, you can c onca tenate c onditions with the && operator for AND, the || opera tor for OR,
and the
The precedence level is !, &&, and ||, with ! ha ving the highe st priority. Like expressions in
high-
evalualevel langua
ted left ges, precedence is
to right.
Expression Evaluation
The assemble r evalua tes conditions crea ted with high-level control struc ture s according to short-circuit
evaluation.
of a partic If the
ular evaluation
condition a utomatically determine s the final result (suc h as a condition tha t
eva luates to false in aAND),
statement concatenated with compound
the evaluation does not continue.
the a ssemble r eva luates the first condition. If this condition is fa lse (that is, if AX is less
than or equal
finished. The secto ond
0), the e valua tion
condition is c hecked and the loop does
is not not execute, bec ause a
compound
requires bothcexpressions
ondition conta
to beining
true for the entire condition to be true.
Procedures
Organizing your code into procedures that execute spe cific tasks divides large pr ograms into managea
ble units,
testing, allowscode
and makes for more
separate
efficient for repetitive tasks.
Assembly-la nguage procedure s are simila r to functions, subroutines, and proce dures in high-leve l languages
such as C, FORTRAN,
and Pascal. Two instructions control the use of assembly-langua ge proce dures. CALL pushes the return address
onto the stack
transfers controland
to a procedure, and RET pops the return address off the stack and returns control to that location.
The PROC and ENDP dire ctives mark the beginning and end of a procedure . Additionally, PROC ca n automa
tically:
Preserve register values tha t should not change but that the procedure might otherwise alter.
Set up a local stack pointer, so that you can acc ess parameters and local variables pla ced on the stack.
Adjust the stack when the procedure ends.
Defining Procedures
Proce dure s require a labe l at the start of the pr oce dure and a RET instruc tion at the end. Procedure s are
normally
the PROC defined bytive
direc usingat the start of the procedure and the ENDP direc tive at the e nd. The
RET instruc tion
immediately normally
be fore is placed
the ENDP directive. The asse mbler makes sure the distanc e of the RET
instruction matches the dista nce
defined by the PROC directive. The basic syntax for PROC is:
The CALL instruction pushes the addre ss of the next instruc tion in your code onto the stack
and pa sses
address. control
The synta x is: to a specified
CALL {labe l | register | memory }
The operand c ontains a va lue calc ulated at run time. Sinc e that ope rand can be a re giste r,
direct
memorymemory
operand, operand, or indirect
you ca n write call tables similar to the example code on page 164.
Calls can be nea r or far. Near calls push only the offse t portion of the calling addr ess and therefore must
ta
thergetsame
a procedure within
segme nt or group. You c an spe cify the type for the targe t ope rand. If you do not,
MASM
(NEAR orusesFAR)the decla re dthat
for operands distance
are labels and for the size of register or memor y ope rands. The assembler then
encodes the casallit does with unconditional jumps. (See previous “Unconditional Jumps” and “Conditional Jumps.”)
appropriately,
MASM optimize s a call to a far non-external la bel when the label is in the curre nt segment by ge
nerating thebyte.
saving one code for a near ca ll,
You can define procedures without PROC and ENDP, but if you do, you must make sure that the size of
the
size of the RET. You can specify the RET instruction as RETN (Return Near) or RETF (Return Far) to override the
default size:
call NEAR PTR task ; Call is decla red near
. ; Return comes to here
.
.
task: ; Procedure begins with near label
.
. ; Instructions go here
.
retn ; Return declared near
The RET instruction (a nd its RETF and RETN variations) a llows an optional constant operand that spec ifies a
number
be added oftobytes
the to
value of the SP register after the re turn. This ope ra nd adjusts for arguments passed to the
procedure before the call,
as shown in the e xample in “Using Loca l Variables,” following.
When you define proce dures without PROC a nd ENDP, you must make sure that calls have
the sameForsizeexample,
returns. a s corRETF
responding
pops two words off the stack. If a NEAR call is made to a procedure
with
value a is far
mereturn, the and
aningless, popped
the stack status may cause the execution to return to a random me
mory
failure. location, r esulting in program
An extended PROC synta x automate s ma ny of the deta ils of ac cessing ar guments and saving re giste rs.
See
with“the
DecPROC
lar ingDirective,”
Parame ters
later in this chapter.
Figure 7.1 shows the stack condition at key points in the process.
Figure 7.1 Proc edure Arguments on the Stack
Sta rting with the 80186 proc essor , the ENTER and LEAVE instructions simplify the stac k setup and
restore
beginninginstructions
and end atof theproce dures. Howe ver, ENTER uses a lot of time. It is necessary only
with nested, Thus,
proc edures. statically-scoped
a Pascal c ompiler may sometim es generate ENTER. T he LEAVE instruction, on the
other
way hand,
to do is thean effic
stac ient
k cleanup. LEAVE r everses the effect of the last ENTER instruc tion by
restoring
before the procedure call.to their va lues
BP and SP
For exam ple, the following diagram shows a valid PROC statement for a proc edure called from C. It ta
kes
and two
arg1, parameters,
and uses (andvar1
must save) the DI and SI registers:
Argument Description
This diagram shows a valid PROC definition that uses several attributes:
Attributes
The syntax for the attributes field is:
distance Controls the form of the RET instruction generated. Ca n be NEAR or FAR. If distance
specifie d, it is dete rmined from the model de clared with the .MODEL directive. NEAR
is assumed for TINY, SMALL, CO MPACT, and FLAT. The a ssemble r a ssumes FAR
distance
distance
for MEDIUM, LARG E, and HUG E. For 80386/486 progra mming with 16- and 32-
segments, you can specify NEAR16, NEAR32, FAR16, or FAR32.
bit
langtype Deter mines the calling conve ntion used to access parameters and restore the sta ck. The
BASIC FORTRAN, and PASCAL langtypes convert proc edure names to uppe rca se, place
the last in the parame ter list lowest on the sta ck, and ge nerate a RET num
parameter
the proc edure.
instruction The RET adjusts the stack upwar d by num, which represents the number of
to end
bytes
in the argument list. This step, called “cleaning the stac k,” re turns the stac k pointer
value
SP toit had
the before the caller pushed any arguments.
The C a nd STDCALL langtype prefixe s an under sc ore to the proce dure name
when the
proce dure’s scope is PUBLIC or EXPORT and places the first par ame ter lowest on
SYSCALL
the stack. is equiva lent to the C calling convention with no underscor e prefixed
to the
proce dure’s nam e. STDCALL uses caller stack cleanup when :VARARG is spec ified; otherwise
the calle d routine must clean up the stack (see Chapter 12).
visibility Indicates whethe r the procedure is available to othe r modules. The visibility can be
PRIVATE, PUBLIC, or EXPORT. A proce dure nam e is PUBLIC unless it is explicitly
declare d asIf the visibility is EXPORT, the linker place s the procedure’s na me
PRIVATE.
table
in thefor segmented
export executables. EXPORT also enables PUBLIC visibility.
You c an explicitly set the default v isibility with the OPTION directive . OPTION
PROC:PUBLIC sets the default to public. For more information, see Chapter 1,
Option
“Using Directive.”
the
prologue arg Specifies the arguments that affec t the generation of prologue a nd epilogue c ode
(the code MASM generates when it encounters a PROC directive or the end of a procedure).
For an
explanation of prologue and epilogue code , see “Generating Prologue and Epilogue
in this chapter.
Code,” later
Parameters
The c omma that separates parameters from reglist is optional, if both fields appe ar on the sa me line. If
parameters
separate line, you must end the reglist field with a comma. In the syntax:
parmname [[:tag]
parmname is the name of the pa rameter. The tag can be the qualifiedtype or the keyword
VARARG
parameter in a list of param-
eters can use the VARARG ke yword. The qualifiedty pe is discussed in “Data T ypes,” Cha pter 1.
An example
reference showing
VARARG how to
param-
eters appear s late r in this section. You c an nest proc edures if they do not have parameters or
USES
shows ra egister lists.
proc edure This diagram
definition with one parameter definition.
The proc edure presente d in “Passing Ar gume nts on the Stack,” page 182, is her e r ewritte n using the
extended
Prior to the procedure c all, you must push the arguments onto the stack unless you use INVOKE.
(See “ Calling
INVOKE,” Procedures
later in with
this chapter.)
In the following exa mple, even though the proc edure de clares the paramete rs as near pointers,
you must code
instructions to gettwothe values of the paramete rs. The first MOV gets the address of the parameters, a nd
the second
parameter.
.MODEL medium, c
.CODE
myadd PROC arg1:NEAR PTR WORD, a rg2:NEAR PTR WORD
ret
myadd ENDP
You can use c onditional-assembly directive s to ma ke sure your pointer pa ra meters are loade d correctly
for the memor
example, y model.
the following For of myadd treats the parame ters as FAR paramete rs, if necessary.
version
ret
myadd ENDP
Using VARARG
In the PROC statement, you can appe nd the :VARARG keyword to the last parameter to indicate
that the pr
variable ocedureofa ccepts
number a
arguments. Howe ver, :VARARG applie s only to the C, SYSCALL, or
STDCALL
Chapte r 12). A symbol must precede :VARARG so the proc edure c an ac cess argume nts as offsets
from
as this the giveillustrates:
example n variable name,
invoke addup3, 3, 5, 2, 4
ret ; Total is in AX
addup3 ENDP
You c an pass non-default- sized pointe rs in the VARARG portion of the pa ra me ter list by sepa ra tely
passing the portion
and the offset segmentofportion
the address.
Note
When you use the extended PROC fea ture s a nd the a ssembler e ncounte rs a RET instruc tion, it automatically
generates instruc
to pop saved tions remove local variables from the sta ck, and, if necessary, remove parameters. It generate s
re gisters,
RET instruction
this code it encounte rs. You can reduce code size by having only one return and jumping to it from
for ea ch
various locations.
Using Local Variables
In high-level languages, local variables a re visible only within a procedure . In Mic rosoft la
nguages, these variables are usua lly
stored on the sta ck. In assembly-language progra ms, you can also have local variables. T hese va ria bles should
not be coronfuse
la bels d with
variable names that are loc al to a module, as described in Chapter 8, “Sharing Data and Proce
dures Among Modules and
Libraries.”
This se ction outlines the sta ndard methods for creating local variables. T he ne xt se ction shows how to use the
ma ke the assembler automa tically gene ra te local variables. When you use this directive, the
assembler
instructions gene ratesdemonstrated
as those the sa mein this section but handles some of the details for you.
If your pr oce dure has relatively few variable s, you can usually wr ite the most e ffic ient code by placing these
value s in registers.
local (stack) Useyou have a large amount of tempora ry data for the procedure.
data when
To use a loca l variable , you must save stack space for it at the start of the proc edure. A procedure can
then r eference
by its positionthein the
va riastac
blek. At the end of the procedure, you must clean the sta ck by restoring
the stac
throws k pointer
away all local. varia
Thisbles effectively
and regains the stack space they occupied.
This example subtracts 2 bytes from the SP register to make room for a local word variable, then accesses the
variable as [bp-2].
push ax ; Push one argument
call task ; Call
.
.
.
Notice the instruction mov sp,bp at the end of the procedure restores the original value of SP. T he statement is
required
value ofonly if the inside the proce dure (usually by allocating local va ria bles). The argument passed to the
SP changes
procedure
with the isRETremovedinstruction. Contra st this to the example in “Passing Arguments on the Stack,” page
182, in the
adjusts which
stackthe calling
for the c ode
a rgument.
To use the LOCAL directive, list the variables you want to c reate, giving a type for e ach one. The assembler
ca lculate
spac s how md uch
e is require on the stack. It also generates instructions to pr operly decrement SP ( as described in the
pre
resetvious section)
SP when and tofrom the procedure.
you return
When you create local va riables this way, your source c ode ca n re fer to e ach loc al variable by na me
rather than a M
stack pointer. s oreover,
an offsettheofassemble
the r generate s de bugging informa tion for e ach local va riable. If you have
progr ammed befor e in
a high-level language that allows sc oping, local va ria bles will seem familiar. For example, a C
compiler sets upclass
automatic storage variable
in the ssame
with
way as the LOCAL directive.
We can simplify the procedure in the previous section with the following code:
The LOCAL directive must be on the line immediately following the PROC statement with the following syntax:
Each vardef defines a local variable. A local variable definition has this form:
label[[ [count]]][[:qualifiedtype ]]
Argument Description
label The name given to the local varia ble. You can use this name to access the variable.
count The number of elements of this name and type to allocate on the stack. You ca n allocate a simple
array on the stac k with c ount. The brac kets around count are required. If this field is omitted, one
data obje ct is assumed.
qualifiedtype A simple M ASM type or a type defined with other type s and attributes. For more
information, see “Data Types” in Chapter 1.
If the number of local var iables exceeds one line, you can place a comma at the end of the first line and continue
the list on
line. Alte the next
rnative ly, you can use se veral consecutive LOCAL directives.
The assembler does not initia lize loca l variables. Your progr am must inc lude code to perform
any necessary
example, initializ
the following ations.
code For sets up a local array and initializes it to zero:
fragment
arraysz EQU 20
Even though you can refe re nce stack variable s by name, the asse mbler treats them as offsets of BP, and they a
re not visible In
the procedure. outside
the following procedure, array is a local variable.
index EQU 10
test PROC NEAR
LOCAL array[index]:WORD
.
.
.
mov bx, index
; mov array[bx], 5 ; Not legal!
The second MOV statement may appear to be legal, but since array is an offset of BP, this statement is the same a s
BP and BX c an be added only to SI and DI. This example would be legal, however, if the index value were moved
to SI of
type or error
DI. This
in your program can be difficult to find unless you keep in mind that local variables in procedures are
offsets of BP.
Declaring Procedure Prototypes
MASM provides the INVOKE directive to ha ndle many of the de tails important to procedure calls,
such a s pushing
according to the parameters
correct calling conventions. To use INVOKE, the procedure c alle d must have be
en
PROC stateme nt, an with
decla red previously a
EXTERNDEF (or EXTERN) statement, or a TYPEDEF. You can also
pla ce a prototype defined with
PROTO before the INVOK E if the procedure type doe s not a ppear before the INVOKE.
Procedure
PROTO informprototypes de fined rwith
the assemble of types and numbers of argume nts so the assembler can
check for errors and pr ovide automatic
conversions when INVOKE ca lls the proce dure.
Decla ring procedure prototypes is good programming practice , but is optional. Prototypes in M ASM
perform thein same
prototypes function
C and other as
high-level languages. A procedure prototype include s the proc edure na me, the types,
and (optiona lly) the
names of all paramete rs the procedur e expe cts. Pr ototypes usua lly are place d at the beginning
of a n assembly
separate program
include file so the or in a encounters the prototype before the actual procedure.
assembler
Prototypes ena ble the assembler to che ck for unmatc hed parame ters and are especia lly use ful for
procedures
modules andca lled
other from other If you write routine s for a libr ary, you may want to put pr ototypes
la nguages.
into an include
proc edures used file
in thatfor all the For more information about using include file s, se e Chapter 8,
library.
“Sharing Data and
among Modules and Pr ocedure
Librarie s.” s
The PROTO directive provides one way to de fine a procedure prototype. The syntax for a prototype definition is
the
procsaedure
me declaration
as for a (see “ Dec la ring Parameters with the PROC Dire ctive,” earlier in this chapter) , except
that youof registers,
the list do not incprologuearg
lude list, or the scope of the procedure.
Also, the PROTO keyword prec edes the langtype a nd distance attributes. The attribute s (like C and FAR
if they a re not spec ified, the defaults are based on any .MODEL or OPTION LANGUAGE
sta tement. a The
parameters re alsonames of but
optional, theyou must list parame ter types. A label preceding :VARARG is also optional in
the
not inprototype
the PROC but
statement.
If a PROTO and a PROC for the same func tion appe ar in the same module , they must match in attribute,
number of par ame
and parameter ters,The ea siest wa y to create prototypes with PROTO is to write your procedure a nd then
types.
copy the c first
line that linethe
ontains (the PROC keyword) to a loc ation in your progra m that follows the data declarations. Cha
nge
and r emove the USES reglist, the prologuearg field, and the v isibility fie ld. It is importa nt
that the prototype
declarations follow
for any types used the
in it to avoid any forward references used by the parameters in the prototype.
The following example illustrates how to define and then de clare two typic al procedures. In both
prototype andthedecla
comma before ration,listthe
argument is optional only when the list does not appear on a separate line:
; Procedure prototypes.
When you call a procedure with INVOKE, the assembler checks the a rgum ents given by
INVOKE
expec ted by the procedure . If the data types of the arguments do not m atch, MASM reports an
error or type.
expected converts
Thesethe type to are
conversions theexplained in the next section.
If arguments do not match in number or if the type is not one the assembler can convert, an error results.
If the procedure uses VARARG, INVOK E can pass a number of arguments different from the
number in the parameter list
without generating a n error or wa rning. Any additional arguments must be at the end of the
INVOKE
arguments must match those in the prototype parameter list.
where expression can be the procedur e’s la be l or an indirec t r eference to a proc edure, and
arguments
register pa ir, or a n expression prece ded with ADDR. (The ADDR operator is discussed later in this chapter.)
The assemble r c an convert some arguments and parameter type combinations so tha t the correct type can be
passe d. The
unsigned signed
qualitie or the arguments in the INVOKE state ments determine how the assembler converts them to
s of
the
by thetypes expe cted
procedure.
The addup proce dure , for example , e xpects pa rameters of type WORD, but the arguments
passed
procedurebycan be any of the se types:
If the type is smaller than that expected by the procedure, M ASM widens the argument to match.
Widening Arguments
For INVOKE to correctly handle type c onversions, you must use the signed data types for any signed
assignments. MASM
an argument to wide
match the nsexpected by a procedure’s parameters in these cases:
type
Type Passe d Type Expected
The assemble r c an extend a segment if far data is expected, and it can c onvert the type given in the list to the types
expected.
assemble rIfcannot
the convert the type, however, it generates an e rror.
Detecting Errors
If the a ssemble r needs to wide n an a rgument, it first copies the value to AL or AX. It widens an unsigne d value
by
theplacing
highe r aregister
zero inarea, and widens a signed value with a CBW, CWD, or CWDE instruc tion as required. Similarly,
the assembler
copies a constant a rgument value into AL or AX whe n the .8086 direc tive is in effect. You c an see the se
generate
the listingd file
instructions in
when you include the /Sg command-line option.
Using the ac cumulator register to wide n or c opy an argument ma y lead to a n error if you attempt to pass AX
as anothe
For exa r a consider
mple, rgument.the following INVOKE sta tement for a proc edure with the C calling convention
where arg is a BYTE varia ble and myproc expects four arguments of type WORD. The assembler widens and the
nthis:
pushes arg like
The generated code thus overwrites the last argument (AX) pa ssed to the proc edure. The assembler gener
ates an e rror
requiring you toinrewrite
this case,
the INVOKE statement.
Passing an Address
You c an use the ADDR opera tor to pass the address of an expression to a proce dure that expe cts a
NEAR
example generates code to pass a far pointer (to arg1) to the proc edure proc1.
For information on defining pointers with TYPEDEF, see “Defining Pointer Types with TYPEDEF” in Chapter 3.
.DATA
pfunc FUNCPTR OFFSET proc1, OFFSET proc2
.CODE
.
.
.
mov bx, OFFSET pfunc ; BX points to table
mov si, Num ; Num contains 0 or 2
INVOKE FUNCPTR PTR [bx+si], arg1 ; Call proc1 if Num=0
; or proc2 if
Num=2
You c an also use ASSUME to acc omplish the sa me task. The following ASSUME statement associates
the type
the BX FUNCPTR with
register.
ASSUME BX:FUNCPTR
mov bx, OFFSET pfunc
mov si, Num
INVOKE [bx+si], arg1
The assemble r a utomatically gener ate s the prologue code when it encounters the first instruc tion or label a fter
the
This means you cannot label the prologue for the purpose of jumping to it. The assemble r
generates
encounters thea epilogue
RET or codeIRET when it
instruction. Using the assemble r-ge nerated prologue and epilogue code
saves
numbertime and decrea
of repetitive sescode
lines of thein your proc edures.
The prologue arg list conta ins options specifying how to gener ate the prologue or epilogue code. The
next section
use the e xplains
se options, how
gives theto standard prologue and epilogue code, a nd expla ins the techniques for defining
your own
epilogue prologue and
code.
The epilogue canc els these three steps in reverse orde r, then cle ans the sta ck, if nec essary,
with a the
example, RETprocedure declaration
push bp ; Ste p 1:
mov bp, sp ; point BP to stack top
sub sp, 4 ; Step 2: space for 2 local words
push di ; Step 3:
push si ; save registers listed in USES
Notice the RET 6 instruction c leans the stack of the three word-size d arguments. The instruc tion appea
rs in the epilogue
the procedure does notbecause
use the C calling convention. If myproc use d C c onventions, the epilogue would end
with a
without an operand.
The assemble r generate s standard e pilogue c ode when it encounters a RET instruc tion without a n operand. It
doe s not if geRET
epilogue neratehas
an a nonzero opera nd. To suppress generation of a sta ndard epilogue, use RETN or
RETF
operand, or use RET 0.
The sta ndard prologue and epilogue code recognizes two oper ands passed in the prologuearg
FORCEFRAME. These operands modify the prologue code. Specifying LOADDS saves and initializes DS.
Specifying
FORCEFRAME a s an argument generates a sta ck frame eve n if no arguments a re sent to the proce dure
and no local
declared. variables
If your are has any pa rameters or locals, you do not need to specify FORCEFRAME.
procedure
For exa mple, adding LOADDS to the a rgument list for myproc c reates this prologue:
push bp ; Ste p 1:
mov bp, sp ; point BP to stack top
sub sp, 4 ; Step 2: space for 2 locals
push ds ; Save DS and point it
mov ax, DGROUP ; to DGROUP, as
mov ds, ax ; instructed by LOADDS
push di ; Step 3:
push si ; save registers listed in USES
The epilogue code restores DS:
To write your own prologue or epilogue code, the OPTION directive must appear in your progra m. It disables
automatic prologue
and epilogue code generation. When you specify
the assembler c alls the macro specified in the OPTION direc tive instead of gene ra ting the sta ndard
prologue andmacro
The prologue epilogue
must cbeode.
a macro function, and the epilogue macro must be a macro procedure.
The assembler expects your prologue or epilogue macro to have this form:
flag, \ parmbyte
s, \ localbyte
s, \ <reglist
>, \ userpa
rms
Your ma cro must have formal parameters to matc h all the actual arguments passed. The arguments passed to your
macro include:
Argument De scription
Your ma cro function must retur n the parmbytes parame te r. However, if the prologue places other values on the
sta
BP ck
andafter pushing
these value s a re not referenc ed by any of the local variable s, the exit va lue must be the number of
bytes
plus any space dure
for proce locaenlsBP and the locals. The refore, parmbytes is not always equal to the bytes occupied by the
betwe
locals.
The following macro is an example of a user-defined prologue that counts the number of times a procedure is called.
.DATA
procname&count WORD 0
.CODE
inc procname&count ; Accumulates count of times the
; procedure is
called push bp
mov bp, sp
; Other BP operations
IFNB <regs>
FOR r, regs
push r
ENDM
ENDIF
EXITM %bytecount
ENDM
Your program must also include this statement before calling any procedure s that use the prologue:
OPTION PROLOGUE:ProfilePro
If you define either a prologue or a n epilogue macro, the asse mbler use s the standard pr ologue or epilogue c
ode for theThe
not define. oneform
youofdo
the code generated depends on the .MODEL and PROC options used.
If you want to revert to the standard prologue or epilogue code , use PROLOGUEDEF or EPILOGUEDEF a s
the
OPTION statement.
OPTION EPILOGUE:EPILOGUEDEF
In this case, no user-de fined macro is c alled, and the assembler does not ge nerate a default code
sequence.
effe ct until This stateOPTION
the next remainsPROLOGUE
in or OPTION EPILOGUE is encountered.
For a dditional information about writing macros, see Chapter 9, “Using Macros.” The
PROLOGUE.INC file provided
MASM 6.1 distr ibution disks in
c anthecreate the prologue a nd epilogue sequence s for the Microsoft
C professional development
system.
MS-DOS Interrupts
In addition to jumps, loops, and procedure s that alter program execution, interrupt routine s
transfer e xecution to a differe nt
location. In this case, control goes to an interrupt routine.
You ca n write your own interrupt routines, eithe r to replace an existing routine or to use an
undefine
example ,d you
interrma
upty number
want .to For
repla ce an MS-DOS interr upt handle r, such as the Critic al Error
(Interrup 24h) and CONTROL+C
(Interrupt 23h) handle rs. The BOUND instruction checks array bounds and calls Interrupt 5 whe n an
error oc curs.
instruction, If youto write
you need use anthisinterrupt handler for it.
The example routine in this section handles addition or multiplication overflow and illustrate s the
steps ne cessa
interrupt ry forForwriting
routine. an information about M S-DOS and BIOS inte rrupts, see Chapter 11,
additional
“Writing
Software.” M emory-Resident
MS-DOS and ROM-BIOS interrupt routines accept data through registers. For instanc e, most MS-DOS
routines
routine s) (and manyaBIOS
re quire function number in the AH register. Many ha ndler routines a lso return values in
register
you must know wha t interrupt,
s. To use an data the handler routine expects and what data, if any, it returns. For information,
consult Help or
other references meone of thein the Introduction.
ntioned
The following fragment illustrates a simple call to MS-DOS Function 9, which displays the string msg on the screen:
.DATA
msg BYTE "This writes to the screen$"
.CODE
mov ax, SEG msg ; Necessary only if DS does not
mov ds, ax ; already point to data segment
mov dx, offset msg ; DS:DX points to msg
mov ah, 09h ; Request Function 9
int 21h
1. Looks up the a ddress of the inte rrupt routine in the Interrupt Ve ctor Table. This ta ble
starts agment
(se 0, offset
t the lowest point0) inand consists of a ser ies of fa r pointers called vectors. Each vector
memory
comprises
(se a 4-byte
gment:offset) pointingaddress
to a n interrupt handler routine. The table sequence implies the number
references: the first the
of the interrupt vectorvector
points to the Inte rrupt 0 handler, the second ve ctor to the Interrupt 1 handler, and
so forth.
vector at Thus, the holds the address of the handler routine for Interrupt i.
0000:i*4
2. Clears the trap flag (TF) and interrupt enable flag (IF).
3. Pushes the flags re giste r, the current code segme nt (CS), a nd the current instruction pointer
(IP), instruction
in that is order. (The
the one currentthe INT statement.) As with a CALL, this ensures control returns to the ne xt
following
the program.
logical position in
4. Jumps to the addre ss of the interrupt routine, as specified in the Interrupt Vector Table.
5. Executes the code of the interrupt routine until it encounte rs an IRET instruction.
6. Pops the instruction pointer, code segment, and flags.