0% found this document useful (0 votes)
29 views

Chapter 7 - Controlling Program

This document discusses various ways to control program flow in assembly language, including jumps, loops, procedures, and interrupts. It explains that jumps transfer control from one point in a program to another by changing the value of the instruction pointer register. There are unconditional jumps, which transfer control without a condition, and conditional jumps, which transfer control based on processor flag status. The document provides examples of jump instructions and optimizations, indirect jump operands, and constructing jump tables. It also covers loop structures like .WHILE and .REPEAT that repeat actions, and procedures that allow passing control between different parts of a program.

Uploaded by

Gyula Solymosi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as RTF, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views

Chapter 7 - Controlling Program

This document discusses various ways to control program flow in assembly language, including jumps, loops, procedures, and interrupts. It explains that jumps transfer control from one point in a program to another by changing the value of the instruction pointer register. There are unconditional jumps, which transfer control without a condition, and conditional jumps, which transfer control based on processor flag status. The document provides examples of jump instructions and optimizations, indirect jump operands, and constructing jump tables. It also covers loop structures like .WHILE and .REPEAT that repeat actions, and procedures that allow passing control between different parts of a program.

Uploaded by

Gyula Solymosi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as RTF, PDF, TXT or read online on Scribd
You are on page 1/ 38

Jumps Top Previous Next

CHAPTER 7

Controlling Program Flow


Very few progra ms exe cute all line s sequentially from .STARTUP to .EXIT. Rathe r, complex program logic and
efficiency
that you dic tate
control the flow of your program — jumping from one point to anothe r, repe ating an a
ction until acontr
and passing condition is from
ol to and reached,
proce dures. This chapter describes various ways for c ontrolling program flow
and
that several fea tureprogram-control
simplify coding s constructs.

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:

; Handle one c ase


label1: .
.
.
jmp continue

; Handle second case


label2: .
.
.
jmp continue
.
.
.
continue:

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 .

jmp [bx] ; Uses .MODEL and se gment size defaults


jmp WORD PTR [bx] ; A NEAR16 indirect call

If the indirect operand is a register, the jump is always a NEAR16 jump for a 16-bit register, and NEAR32

jmp bx ; NEAR16 jump


jmp ebx ; NEAR32 jump

A DWORD indirect operand, howeve r, is ambiguous to the assembler.

jmp DWORD PTR [var] ; A NEAR32 jump in a 32-bit segment;


; a FAR16 jump in a 16-bit segment

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.

NPVOID TYPEDEF NEAR PTR


.DATA
ctl_tbl NPVOID extended, ; Null key (exte nded c ode)
ctrla, ; Address of CONTROL-A key routine
ctrlb ; Address of CONTROL-B key routine
.CODE
.
.
.
mov ah, 8h ; Get a key
int 21h
cbw ; Stretch AL into AX
mov bx, ax ; Copy
shl bx, 1 ; Convert to address
jmp ctl_tbl[bx] ; Jump to ke y routine

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

Jumping Based on the CX Register


JCXZ and JECXZ are special conditional jumps tha t do not c onsult the processor flags.
Instead,
instructionsas cause
the ira name
jump s only
imply, theseCX or ECX r egister is zero. The use of JCXZ and JECXZ with
if the
progra
the nextmsection,
loops “Loops.”
is cove red in

Jumping Based on the Processor Flags


The r ema ining conditional jumps in the proc essor’s repertoire all depe nd on the status of the fla
gs r egister.
shows, severalAs conditional
the following
jumpslist have two or three name s — JE (Jump if Equal) and JZ (Jump
if Zero),assemble
names for example. Shar
to exa ctly theedsa me mac hine instruction, so you may choose whichever mne monic seems
more appropriate.
that depe nd on theJumps
status of the flags register include:

Instruction Jumps if

JC/JB/JNAE Carry flag is set


JNC/JNB/JAE Carry flag is clear
JBE/JNA Either carry or zero flag is set
JA/JNBE Carry and zero flag are clea r
JE/JZ Zero flag is set
JNE/JNZ Zero flag is clear
JL/JNGE Sign fla g overflow flag
JGE/JNL Sign fla g = overflow flag
JLE/JNG Zero flag is set or sign overflow
JG/JNLE Zero flag is clear and sign = overflow
JS Sign fla g is set
JNS Sign fla g is clear
JO Overflow flag is set
JNO Overflow flag is clear
JP/JPE Parity flag is set (even parity)
JNP/JPO Parity flag is clear (odd parity)

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

There a re three categories of c onditional jumps:

Comparison of two values


Individual bit settings in a value
Whether a value is zero or nonzero

Jumps Based on Comparison of Two Values


The CMP instruc tion is the most common way to te st for conditional jumps. It compares two value s without
changing eithethe
sets or clears r, processor
then flags according to the results of the c omparison.

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.

Table 7.1 Conditional Jumps Based on Comparisons of Two Values

Signed Comparisons Unsigned Comparisons


Instruction Jump if True Instruction Jump if True

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.

cmp ax, bx ; Compare AX and BX


jg next1 ; Equivalent to: If ( AX > BX ) goto next1
jl next2 ; Equivalent to: If ( AX < BX ) goto next2

Jumps Based on Bit Settings


The individual bit settings in a single va lue ca n also se rve as the c rite ria for a conditional jump. The TEST
specific bits in an operand are on or off (se t or clear), and sets the zero flag acc ordingly.

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,

Jumps Based on a Value of Zero


A program ofte n needs to jum p based on whether a particular registe r conta ins a value of
zero. Wejumps
instruction ’ve seedepe
n how
nding theon the value in the CX register. You c an test for ze ro in other data r egisters ne
arly
the ORasinstruction.
efficientlyA with
program can OR a register with itself without c hanging the register’s contents, then a ct on
the resulting
status. flags the following example tests whether BX is zero:
For example,

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

or dx, dx ; Is DX sign bit set?


js sign_set ; Jump if so

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:

; Jump to target less than 128 bytes awa y


jz target ; If previous ope ration resulted
; in zero, jump to
target
However, if ta rget is too distant, the following sequence is ne cessary to enable a longer
jump. Note
equivalent thispreceding
to the sequence is logically
example:

; 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:

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:

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


jmp NEAR PTR target

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

jz NEAR PTR target


becomes
jne $+5
jmp NEAR PTR target
even if target is less than 128 bytes away.

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.

The jump in the following example targets an anonymous label:

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

The decision structure


.IF cx == 20
mov dx, 20
.ELSE
mov dx, 30
.ENDIF

generates this code:

.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.

The following e xamples illustrate these loop constructions.

; The LOOP instruction: For 200 to 0 do task


mov cx, 200 ; Set counter
next: . ; Do the task here
.
.
loop next ; Do again
; Continue after loop
; The LOOPNE instruction: While AX is not 'Y', do task
mov cx, 256 ; Set count too high to interfe re
wend: . ; But don't do more than 256 times
. ; Some statements that change AX
.
cmp al, 'Y' ; Is it Y or too many times?
loopne wend ; No? Repeat
; Yes?
Continue
The JCXZ and JECXZ instructions provide an efficient wa y to a void executing loops when the loop
counter
example,CX is empty.
consider For loops:
the following

mov cx, LoopCount ; Load loop counter


next: . ; Iterate loop CX times
.
.
loop next ; Do again

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:

mov cx, LoopCount ; Load loop counter


jcxz done ; Skip loop if count is 0
next: . ; Else iterate loop CX times
.
.
loop next ; Do again
done: ; Continue after loop

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.

ASSUME bx:PTR SomeStruct

.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

.BREAK and .CONTINUE Directives


The .BREAK and .CONTINUE directive s te rminate a .REPEAT or .WHILE loop prem aturely.
These
optionaldirectives allow
.IF clause for an
conditional breaks. The synta x is:

.BREAK [[.IF condition]]


.CONTINUE [[.IF condition]]

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.

.WHILE 1 ; Loop forever


mov ah, 08h ; Get key without echo
int 21h
.BREAK .IF al == 13 ; If ENTER, break out of the loop
.CONTINUE .IF (al < '0') || (al > '9')
; If not a digit, continue looping
mov dl, al ; Save the character for processing
mov ah, 02h ; Output the character
int 21h
.ENDW

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.

Writing Loop Conditions


You can express the conditions of the .IF, .REPEAT, and .WHILE dire ctive s using relational operators, and
you c an expre
attributes of thessoperand
the with the PTR operator. To write loop conditions, you also need to know how the
assembler
operators andevaoperands
luates the
in the condition. This section e xplains the operator s, a ttributes, precedence le vel, and
expression
order for the evaluation
conditions used with loop-generating directives.

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

Signed and Unsigned Operands


Expression operators generate unsigned jumps by default. However, if eithe r side of the
operation is entire
considers the signed, the assembler
operation signed.

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:

.WHILE SWORD PTR [bx] <= 0


.IF SWORD PTR mem1 > 0

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.

For exa mple, in this .WHILE statement,

.WHILE (ax > 0) && (WORD PTR [bx] == 0)

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:

label PROC [[NEAR | FAR]]


.
.
.
RET [[constant]]
label ENDP

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 syntax for RETN and RETF is:

label: | labe l LABEL NEAR


statements
RETN [[constant]]
label LABEL FAR
statements
RETF [[constant]]

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.

Passing Arguments on the Stack


Each time you call a procedure , you may want it to operate on different da ta. This data , calle d
“arguments,”
proc edure in cvarious
an be wa
passed to the you can pass ar gume nts to a proc edure in register s or in variables, the
ys. Although
most common
is the sta method
ck. Mic rosoft language s have specific c onventions for passing arguments. These
conventions for with
modules shared assembly-langua
modules fromge high-leve l languages are explained in Chapter 12, “Mixed-Language
Programming.”
This sec tion describes how a procedure acce sses the a rguments passed to it on the stack. Each a
rgument
from BP. isHowever,
ac ce ssedif you
as use
an offset
the PROC direc tive to de clare pa rameters, the assembler calcula tes these offsets
for
referyoutoandparameters
lets you by name. T he next se ction, “Decla ring Parameters with the PROC Dire ctive,” expla
ins how to use
way. This example shows how to pass ar guments to a pr ocedure . The proc edure expects to find those
arguments
this exampleon the arguments
shows, stack. Asmust be ac cessed as offse ts of BP.

; C-style procedure call and definition

mov ax, 10 ; Load and


push ax ; push constant a s third argument
push arg2 ; Push memory as second argument
push cx ; Push register as first argument
call addup ; Call the procedure
add sp, 6 ; Destroy the pushed arguments
. ; (equivalent to three pops)
.
.
addup PROC NEAR ; Return address for near call
; takes two
bytes push bp ; Save base pointer - takes two bytes
; so arguments start a t fourth byte
mov bp, sp ; Load stack into base pointe r
mov ax, [bp+4] ; Get first argument from
; fourth byte above pointer
add ax, [bp+6] ; Add second argument from
; sixth byte above pointer
add ax, [bp+8] ; Add third argument from
; eighth byte above pointer
pop bp ; Restore BP
ret ; Return result in AX
addup ENDP

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

Declaring Parameters with the PROC Directive


With the PROC directive, you can spec ify registers to be saved, define param-
eters to the proc edure, and a ssign symbol na mes to parameters (rather than as offsets from BP). This
section
the PROCdescr ibes how
directive to use the parameter-accessing techniques described in the last section.
to automate

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:

The syntax for PROC is:

label PROC [[attributes]] [[USES reglist]] [[, ]] [[parameter[[:tag]]... ]]

The parts of the PROC directive include:

Argument Description

label The name of the procedure.


attributes Any of several attributes of the proce dure, including the distanc e, langtype, and v isibility
procedure. The syntax for attributes is given on the following page.
reglist A list of registers following the USES keyword that the proc edure use s, and that should
be saved on entry. Registers in the list must be separated by blanks or ta bs, not by
commas. The
assembler gene ra tes prologue c ode to push these register s onto the stack. When
assembler
you exit, generates
the epilogue code to pop the saved register values off the stack.
parameter The list of parameters passed to the proc edure on the stack. The list ca n have a va ria ble number
of parame ters. See the discussion following for the syntax of parameter. T his list can be
longer
than one line if the continued line ends with a comma.

This diagram shows a valid PROC definition that uses several attributes:

Attributes
The syntax for the attributes field is:

[[distance]] [[langtype]] [[visibility]] [[<prologue arg>]]

The explanations for these options include:


Argument Description

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.)

addup PROC NEAR C,


arg1:WORD, a rg2:WORD, count:WORD
mov ax, arg1
add ax, count
add ax, arg2
ret
addup ENDP
If the a rguments for a proce dure are pointers, the a ssembler doe s not ge nerate any code to get the
value
refere or values
nce; that program
your the pointersmust still explicitly tre at the argument a s a pointer. (For more
information a bout
Chapter 3, “Using using pointers,
Addresses see
and Pointers.”)

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.

; Call from C as a FUNCTION returning an integer

.MODEL medium, c
.CODE
myadd PROC arg1:NEAR PTR WORD, a rg2:NEAR PTR WORD

mov bx, arg1 ; Load first argument


mov ax, [bx]
mov bx, arg2 ; Add second argument
add ax, [bx]

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

.MODEL medium, c ; Could be any model


.CODE
myadd PROC arg1:PTR WORD, arg2:PTR WORD
IF @DataSize
les bx, arg1 ; Far parameters
mov ax, es:[bx]
les bx, arg2
add ax, es:[bx]
ELSE
mov bx, arg1 ; Near parameters
mov ax, [bx]
mov bx, arg2
add ax, [bx]
ENDIF

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,

addup3 PROTO NEAR C, argcount:WORD, arg1:VARARG

invoke addup3, 3, 5, 2, 4

addup3 PROC NEAR C, argcount:WORD, arg1:VARARG


sub ax, ax ; Clear work register
sub si, si

.WHILE argcount > 0 ; Argcount has number of argume nts


add ax, arg1[si] ; Arg1 has the first argument
dec argcount ; Point to next argument
inc si
inc si
.ENDW

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
.
.
.

task PROC NEAR


push bp ; Save base pointer
mov bp, sp ; Load stack into base pointer
sub sp, 2 ; Save two bytes for local va riable
.
.
.
mov WORD PTR [bp-2], 3 ; Initializ e local variable
add ax, [bp-2] ; Add local varia ble to AX
sub [bp+4], ax ; Subtract local from argument
. ; Use [bp-2] and [bp+4] in
. ; other
.
operations
mov sp, bp ; Clear local variables
pop bp ; Restore base
ret 2 ; Return result in AX and pop
task ENDP ; two bytes to clear para meter

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.

Figure 7.2 shows the stack at key points in the process.


Figure 7.2 Local Variables on the Stack

Creating Local Variables Automatically


MASM’s LOCAL directive automates the process for crea ting local variables on the sta ck.
LOCAL
count stack frees words,
you from
a nd having
it ma to kes your code e asier to write and m aintain. This sec tion
illustrates the advantages of cre
temporary data with the LOCAL directive. ating

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:

task PROC NEAR arg:WORD


LOCAL loc:WORD
.
.
.
mov loc, 3 ; Initialize local variable
add ax, loc ; Add local variable to AX
sub arg, ax ; Subtra ct local from argument
. ; Use "loc" and "arg" in other ope rations
.
.
ret
task ENDP

The LOCAL directive must be on the line immediately following the PROC statement with the following syntax:

LOCAL vardef [[, vardef]]...

Each vardef defines a local variable. A local variable definition has this form:

label[[ [count]]][[:qualifiedtype ]]

These are the parameters in local variable definitions:

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

aproc PROC USES di


LOCAL var1[arraysz]:WORD, va r2:WORD
.
.
.
; Initialize local array to zero
push ss
pop es ; Set ES=SS
lea di, var1 ; ES:DI now points to array
mov cx, arraysz ; Load count
sub ax, ax
rep stosw ; Store zeros
; Use the array...
.
.
.
ret
aproc ENDP

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

; mov [bp + bx + arrayoffset], 5 ; Not legal!

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.

addup PROTO NEAR C argcount:WORD, arg2:WORD, arg3:WORD


myproc PROTO FAR C, argcount:WORD, arg2:VARARG
; Procedure declarations

addup PROC NEAR C, argcount:WORD, arg2:WORD, arg3:WORD


.
.
.
myproc PROC FAR C PUBLIC <callcount> USES di si,
argcount:WORD,
arg2:VARARG

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.

Calling Procedures with INVOKE


INVOK E generates a sequence of instructions that push ar guments and call a procedure. This helps
maintain code
langtype for if arguments
a procedure or
are changed. INVOKE generates procedure calls and automatically:

Converts arguments to the expected types.


Pushes arguments on the stack in the correct order.
Clea ns the stack when the procedure returns.

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.

The syntax for INVOKE is:

INVOKE expression [[, arguments]]

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.)

Procedure s with these prototypes

addup PROTO NEAR C argcount:WORD, arg2:WORD, arg3:WORD


myproc PROTO FAR C, argcount:WORD, arg2:VARARG

and these procedure declarations

addup PROC NEAR C, argcount:WORD, a rg2:WORD, arg3:WORD


.
.
.
myproc PROC FAR C PUBLIC <callcount> USES di si,
argcount:WORD,
arg2:VARARG

can be called with INVOKE statements like this:

INVOKE addup, ax, x, y


INVOKE myproc, bx, cx, 100, 10

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:

BYTE, SBYTE, WORD, or SWORD


An expression whose type is specified with the PTR operator to be one of those types
An 8-bit or 16-bit register
An immediate expression in the range –32K to +64K
A NEAR PTR

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

BYTE, SBYTE WORD, SWORD, DWORD, SDWORD


WORD, SWORD DWORD, SDWORD

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

INVOKE myprocA, ax, cx, 100, arg

where arg is a BYTE varia ble and myproc expects four arguments of type WORD. The assembler widens and the
nthis:
pushes arg like

mov al, DGROUP:arg


xor ah, ah
push ax

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.

To summarize, the INVOKE directive ove rwrite s AX a nd pe rhaps DX when widening a


rguments.
constants onIt the
also 8088
uses and
AX 8086.
to push
If you use these registers (or EAX and EDX on an 80386/486)
to pass arguments, they may be
overwritten. The a ssembler’ s error detection prevents this from ever becoming a run- time bug, but AX and DX
should remain
last c hoice for your
holding a rguments.

Invoking Far Addresses


You c an pass a FAR pointer in a segment::offset pair, as shown in the following. Note the use of
double colons
register pa ir. Theto registers
se paratecould
the be any other re gister pair, including a pair that an MS-DOS call uses to return
values.
FPWORD TYPEDEF FAR PTR WORD
SomeProc PROTO var1:DWORD, var2:WORD, var3:WORD

pfaritem FPWORD faritem


.
.
.
les bx, pfaritem
INVOKE Some Proc, ES::BX, a rg1, arg2
However, INVOKE cannot combine into a single address one argument for the segment and one for the offset.

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.

PBYTE TYPEDEF FAR PTR BYTE


arg1 BYTE "This is a string"
proc1 PROTO NEAR C fparg:PBYTE
.
.
.
INVOKE proc1, ADDR arg1

For information on defining pointers with TYPEDEF, see “Defining Pointer Types with TYPEDEF” in Chapter 3.

Invoking Procedures Indirectly


You can m ake an indir ect procedure call such as call [bx + si] by using a pointer to a function prototype with
in this example:

FUNCPROTO TYPEDEF PROTO NEAR ARG1:WORD


FUNCPTR TYPEDEF PTR FUNCPROTO

.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

Checking the Code Generated


Code ge nerated by the INVOKE dire ctive may vary depending on the processor mode and calling
conventions in effect.
check your listing You
files to cancode generated by the INVOKE dire ctive if you use the /Sg command-line
see the
option.

Generating Prologue and Epilogue Code


When you use the PROC directive with its extended syntax and argument list, the asse mbler automatically
generates the code
and epilogue prologue
in your procedur e. “Prologue c ode” is generated at the start of the procedure. It se
ts
can acc ess parameters sofrom
up a stack pointer you within the procedure . It also saves space on the stack for local var
iables,
DS, andinitializes
pushes registers
re gisters such
thata sthe procedur e use s. Similarly, “epilogue code” is the code at the
end of and
registers the returns
pr ocedure that
from the pops
proce dure.

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 generated prologue or epilogue code depends on the:

Local variables define d.


Arguments passed to the procedure.
Current processor selected (affects epilogue code only).
Current calling convention.
Options passed in the prologuearg of the PROC directive.
Registers being sa ved.

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.

Using Automatic Prologue and Epilogue Code


The standa rd prologue and epilogue code handle s pa ra meter s a nd local variables. If a procedure does
not
local have anytheparameters
variables, prologueorand epilogue code that sets up and restores a stack pointer is omitted, unless
FORCEFRAME is included in the prologuearg list. (FORCEFRAME is discussed later in this
section.) Pr ologuea apush
code also generates nd and
epilogue
pop for each register in the register list.

The prologue code consists of three steps:

1. Point BP to top of stack.


2. Make space on stack for local va riables.
3. Save registers the procedure must preserve.

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

myproc PROC NEAR PASCAL USES di si,


arg1:WORD, a rg2:WORD, arg3:WORD
LOCAL local1:WORD, loca l2:WORD

generates the following prologue code:

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

The corresponding epilogue code looks like this:

pop si ; Undo Step 3


pop di
mov sp, bp ; Undo Step 2
pop bp ; Undo Step 1
ret 6 ; Clean stack of pushed arguments

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:

pop si ; Undo Step 3


pop di
pop ds ; Restore DS
mov sp, bp ; Undo Step 2
pop bp ; Undo Step 1
ret 6 ; Clean stack of pushed arguments

User-Defined Prologue and Epilogue Code


If you want a diffe re nt se t of instr uctions for prologue a nd epilogue code in your proc edures, you c an write ma
cros that run
of the in placeprologue a nd e pilogue code. For example , while you are de bugging your proce
standard
dures, you or
stack check ma ytrawant
ck theto number
includeof atimes a proce dure is c alled. You ca n write your own prologue c ode to do
these
a procethings
dur ewhenever
exe cutes. Diffe rent prologue code may also be necessary if you a re writing a pplica
tions for Windows. User-defined
prologue macros will respond correctly if you specify FORCEFRAME in the prologuearg of a procedure.

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

OPTION PROLOGUE : macroname


OPTION EPILOGUE : macroname

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:

macroname MACRO procname, \

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

procname The name of the procedure.


flag A 16-bit flag containing the following information:
Bit = Value Description
Bit 0, 1, 2 For calling conve ntions ( 000=unspec ified langua ge type, 001=
010=SYSCALL, 011=STDCALL, 100=PASCAL, 101=FORTRAN
110=BASIC).
Bit 3 Undefined (not necessarily ze ro).
Bit 4 Set if the caller restores the stack (use RET, not RETn).
Bit 5 Set if procedure is FAR.
Bit 6 Set if procedure is PRIVATE.
Bit 7 Set if procedure is EXPORT.
Bit 8 Set if the epilogue is ge nerated a s a result of an IRET instruc tion and cleared
if the epilogue is generated as a result of a RET instruction.
Bits 9–15 Undefined (not necessarily ze ro).
parmbytes The accumulated count in bytes of all parameters given in the PROC statement.
localbytes The count in bytes of all locals defined with the LOCAL directive.
reglist A list of the registers following the USES operator in the procedure dec laration. Enclose this list
with angle brackets (< >) and separate each item with commas. Reverse the list for epilogues.
userparms Any argument you want to pass to the macro. The prologuearg (if there is one) spe cified
in the PROC directive is passed to this argument.

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.

ProfilePro MACRO procname, \


flag,
\ bytecount,
\ numloc als,
\ regs,
\ macroargs

.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

You can completely suppress prologue or epilogue generation with

OPTION PROLOGUE:None OPTION EPILOGUE:None

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.

This section summarizes the following:

How to call interrupts


How the processor ha ndles inte rrupts
How to redefine an existing interrupt routine

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

Calling MS-DOS and ROM-BIOS Interrupts


Inte rrupts provide a way to a ccess MS-DOS and ROM -BIOS from assembly language . They a re calle
dwhich
with takes
the an immediate value between 0 and 255 as its only operand.

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

When the INT instruction executes, the processor:

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.

Figure 7.3 illustrates how interrupts work.

Figure 7.3 Operation of Interrupts

Replacing an Interrupt Routine


To replace an existing interrupt routine, your program must:

Provide a ne w routine to handle the interrupt.


Replace intothe old routine’s address in the ;Interrupt
Call Interrupt
Vector4 Table
if overflow
with the address of your new routine.
Replace . the old addre ss back into the vector table before your program ends.
.
You can. write an inte rrupt routine a s a proc edure by using the PROC and ENDP directives. The routine should
always lds de fineddx, vector ; Load original address
as FARbe and should e nd with an IRET instruction instea d of a RET instruction.
mov ax, 2504h ; Restore it to vector table
int 21h ; with DOS set ve ctor function
Note
mov ax, 4C00h ; Terminate function
You canintuse the 21hfull extended PROC syntax (described in “Declaring Parameters with the PROC Directive ,” earlier
to writechapte
in this interrupt
r) procedur es. However, you should not make interrupt proce dures NEAR or specify a rguments
for them.
use the USES You can keyword, however, to corre ctly genera te code to save and restore a register list in interrupt
procedures.
ovrflow PROC FAR
The IRET instruction in MASM 6.1 has two forms tha t suppress epilogue code. This allows an interrupt to
sti ; Enable
have loc al variables
use a user-defined or
prologue. IRETF pops;a FAR16
interrupts (turnedreturn
off byaddress, and IRETFD pops a FAR32 return address.
INT) mov ah, 09h ; Display string function
The following
mov example
dx, OFFSET shows
msg how to ;r Load eplaceaddress
the handler for Inter rupt 4. Once register ed in the
Interrupt Vector
routine inttake s 21h Table, the new
control when the proce; Call ssor encounters either a n INT 4 instruction or its special
DOS
variationsub ax, ax ; Set AX to 0
Overflow). INTO is a c onditional instruction that acts only when the overflow fla g is set. With INTO after a
cwd ; Set DX
numerical
your calculation,
to 0 code iret can automatically route ; c ontrol to a handler routine if the ca lculation results in a
nume
routinericENDP
ovrflow
Return al Interrupt
for over flow. By de fault,
4 simply the of an IRET, so it returns without doing anything. Using INTO is an a
consists
ENDto using
lternative
(Jump on Overflow) to jump to another se t of instructions.

Before the progra m


The following ends, it aga
example in use sfirst
program M S-DOS Function
exe cutes INT25h 21hto to
r esetinvoke
the original Interrupt
MS-DOS 4 vector35h
Function ba ck(Get
into
the Inter
Interr rupt Vec tor
returnsupt
Table. theVector)
This . This
reestablishes
existing vecfunction
the original
tor forroutine as the4.handler
Interrupt The for
pr Interrupt 4.
ogram stores the ve ctor, the n invokes M S-
DOS
Vector) Functo tion
place25hthe(Set Inte rruptthe ovrflow procedure in the Interrupt Vector Table. From this
The first instr uction of the address
ovrflow rof outine warra nts further discussion. Whe n the proce ssor encounters an
point
wheneveron, ovrflow
theflag
processorgains control
the interrupt be foreexebranching
cutes INTO while
to the theified
spec overflow
interruptflag is set.routine.
handler The new routine
The displa
inter rupt flagysserves
a message a nd
a crucial
retur
role
DX ns
in with AX
smoothing and
to 0. tasks,the
procset
essor’s but must not be abused. Whe n clear, the flag inhibits hardware interrupts such as the keyboard
or systembetime
should le r.ft It clear only briefly and only whe n absolutely ne cessa ry. Unless you have a c ompelling
.MODEL LARGE, C
reason
FPFUNC to leave
always includeTYPEDEF the flag
FAR c lear,
PTR
an STI (Set Interrupt Flag) instruc tion a t the beginning of your interrupt
handler .DATA
routine to re enable hardware
interrupts.
msg BYTE "Overflow - result set to 0",13,10,'$'
vector FPFUNC ?
.CODE
.STARTUP
CLI (Clear Interrupt Flag) a nd its corollary STI a re designed to protect small sections of time-
dependent codeax, from
by themovhardware. If inte
3504h yourruptions
use CLI; Loaind Interrupt
your program,
4 and c all DOS
be sure to include a matching STI
int
instruction as 21hwell. The sample ;
inte Get
rrupt Interrupt Vector
handlers in Chapter 11, “Writing Memory-Resident Software,” illustrate how to use these important instructions.
mov WORD PTR vector[2],es ; Save segment
mov WORD PTR vector[0],bx ; and offset
push ds ; Save
DS mov ax, cs ; Load segment of new routine
mov ds, ax
mov dx, OFFSET ovrflow ; Load offset of new routine
mov ax, 2504h ; Loa d Interrupt 4 and c all DOS
int 21h ; Set Interrupt Vector
pop ds ;
Restore.
.
.
add ax, bx ; Do arithmetic

You might also like