.8086 Directive
PURPOSE:
Use .8086 to inform MASM to allow instructions available on the 8088 and 8086 processors only. This also enables the assembly of instructions specific to the 8087 floating-point processor.
SYNTAX:
.8086
COMMENTS:
By default, MASM accepts instructions specific to the 8088, 8086, and 8087 processors only. Selecting this default instruction set ensures that your program can run on all MS-DOS systems, but it also means that you cannot take advantage of the new and advanced features of the 80286, 80386, 80287, 80387, 80486, 80586, etc. processors. A better solution is to detect the processor present in the system and use the instructions for newer processors when the conditions permit.
SEE ALSO:
.8087, .NO87, .186, .286, .286P, .287, .386, .386P, .387, .486, .486P, .586, .586P, .686, .686P
EXAMPLE:
Normally you do not have to use the .8086 directive because it is active by default. However, if you use any 30836-specific instructions in your program, you may want to keep them confined in a section, as shown in the following example. This way you can be certain that all 80386-specific code is in one place because MASM generates an error message if you use them anywhere else.

; ---------- Start of 80386 specific code ----------
   .386

; all 80386 code such as 32-bit moves, bit tests, etc., go here
   movsx eax, bx ; copy BX to EAX with sign extension
   .
   .
   mov cx, 10                  ; bit number to CX
   btr WORD PTR ErrorCode, cx  ; copy bit to CF and reset
   .
   .
; ------------ End of 80386 specific code ----------

; back to plain vanilla 8086
   .8086


.8087 Directive
PURPOSE:
Use .8087 to enable assembly of instructions specific to the 8087 floating-point coprocessor and disable the assembly of instructions for the 80287 and 80387 coprocessors. The .8087 directive also specifies the IEEE format for binary representation of floating-point numbers.
SYNTAX:
.8087
COMMENTS:
MASM accepts 8087 instructions by default. The .8087 directive is provided so that if your program uses the instructions of all math coprocessors (8087, 80287, 80387, 80487, etc.), you can revert back to the instruction set of 8087 when necessary.
SEE ALSO:
.8086, .NO87, .186, .286, .286P, .287, .386, .386P, .387, .486, .486P, .586, .586P, .686, .686P
EXAMPLE:
in the following example the .8087 directive is used after a block of 80387-specific instructions to revert back to the 8087.

; ---------- Start of 80386 specific code ----------
   .387

   fldpi      ; load "pi"
   fsin       ; take its sine
   .
   .
; ------------ End of 80386 specific code ----------

; back to plain vanilla 8087
   .8087


.186 Directive
PURPOSE:
Use .186 to direct MASM to accept instructions specific to the 80186 processor in addition to the basic 8086 and 8087 instructions.
SYNTAX:
.186
COMMENTS:
The 80186 instruction set is a superset of the 8086 instructions. For example, the 80186 has a PUSH immediate_value instruction which the 8086 does not allow.

SEE ALSO:
.8086, .8087, .NO87, .286, .286P, .287, .386, .386P, .387, .486, .486P, .586, .586P, .686, .686P

EXAMPLE:
Suppose you want to use the push instruction with an immediate operand (which is legal in processors later than the 80186). You can do so provided you place a .186 directive before the instruction.
    .186
    push 4   ; allowed on 80186 and above

.286 Directive
PURPOSE:
Use .286 to ask MASM to accept instructions specific to the real mode operation of the 80286 processor in addition to the basic 8086 and 80186 instructions. This also enables the assembly of 80287 instructions.
SYNTAX:
.286
COMMENTS:
The .286 directive is similar to the .286C directive in previous versions of MASM. The .286 directive disables the assembly of protected mode instructions specific to the 80286 even if they were previously enabled with a .286P directive.
SEE ALSO:
.8086, .8087, .NO87, .186, .286P, .287, .386, .386P, .387, .486, .486P, .586, .586P, .686, .686P
EXAMPLE:
    .286            ; enable 80386 specific instructions
    movsx eax, bx   ; copy BX to EAX with sign extension

.286P Directive
PURPOSE:
Use .286P to enable the assembly of instructions specific to the protected mode operation of the 80286 processor in addition to the instructions for the 8086, 80186, and 80286 in real mode. The .286P directive also enables assembly of 80287 instructions.
SYNTAX:
.286P
COMMENTS:
The protected mode instructions are used in writing operating system software. Application programs do not use these privileged instructions that manage multiple processors.
SEE ALSO:
.8086, .8087, .NO87, .186, .286, .287, .386, .386P, .387, .486, .486P, .586, .586P, .686, .686P
EXAMPLE:
    .286P        ; enable 80286's privileged instructions
    lgdt    ax   ; a privileged instruction

.386 Directive
PURPOSE:
Use .386 to ask MASM to accept the nonprivileged instructions of the 80386 processor in addition to the basic 8086, 80186, and 80286 instructions. This also enables the assembly of 80387 instructions.
SYNTAX:
.386
COMMENTS:
The .386 directive disables the assembly of protected mode instructions specific to the 80386 even if they were previously enabled with a .386P directive. You should use the .386 directive if your program is meant for the 80386-based system only.
SEE ALSO:
.8086, .8087, .NO87, .186, .286, .286P, .287, .386P, .387, .486, .486P, .586, .586P, .686, .686P
EXAMPLE:
    .386            ; enable 80386 specific instructions
    movsx eax, bx   ; copy BX to EAX with sign extension

.CODE Directive
PURPOSE:
Use .CODE to define the start of the code segment. You must select a memory model with a .MODEL directive before using the .CODE directive. When you plan to use more than one code segment, you have to specifiy a name for each one. The name is optional when there is only one code segment.
SYNTAX:
.CODE [name]
COMMENTS:
You should place all processor instructions in a segment initiated with the .CODE directive.
SEE ALSO:
ASSUME, SEGMENT, ENDS, .DATA, .STACK, .MODEL
EXAMPLE:
        .MODEL SMALL       ; must precede .CODE, .DATA, or .STACK
        .CODE              ; start code segment
Start:
        mov    ax, @data
        mov    ds, ax
        mov    ax, Var1
        .                  ; other instructions
        .
        .CONST             ; segment for constants
Message DB     "Press any key to continue...$"
        .DATA              ; switch to data segment
Var1    DW     8
        .STACK 512         ; define a 512 byte stack segment
        END    Start       ; mark end of program

.DATA Directive
PURPOSE:
Use .DATA to define the start of a data segment named _DATA for initialized data. The .DATA? directive begins a data segment named _BSS for uninitialized data. You must select a memory model with a .MODEL directive before using the .DATA and .DATA? directives.
SYNTAX:
.DATA
.DATA?
COMMENTS:
If a procedure writtne in assembly language will be called from a high-level language, you should follow the convention of placing initialized and uninitialized data in segments defined by .DATA and .DATA?, respectively. In stand-alone assembly language programs, these segments are not necessary. Note that the segments started by .DATA, .DATA?, .CONST, and .STACK are placed in the group named DGROUP. Thus, you should use DGROUP to initialize the DS register when accessing in those segments.
SEE ALSO:
.CODE, .STACK, .MODEL, ASSUME, SEGMENT, ENDS, GROUP
EXAMPLE:
See example for .CODE

.DOSSEG Directive
PURPOSE:
Use .DOSSEG to order segments according to the convention used in MS-DOS.
SYNTAX:
DOSSEG
.DOSSEG
COMMENTS:
Segment-ordering defines how the segments are laid out in memory when the program is loaded for execution. The DOS segment-ordering convention is alos followed by Microsoft's high-level languages such as C and FORTRAN. Since order of segments is not critical in assembly language programs, you can safely use the .DOSSEG directive in such programs.
SEE ALSO:
.ALPHA, .SEG
EXAMPLE:
    .DOSSEG
    .MODEL SMALL

.IF Directive
PURPOSE:
The .IF macro is a high-level decision mechanism added to MASM 6.0. MASM expands this statement to produce comparable assembly language code which tests a condition and executes or skips a section of code depending upon the result of the comparison. It is very similar to the IF..THEN..ELSEIF..ELSE statements in various high-level languages.
SYNTAX:
.IF expression
COMMENTS:
Do not confuse the high-level .IF statement with the conditional assembly directives provided in MASM. The conditional assembly directives control which sections of code MASM actually assembles. The .IF macro controls which statements actually execute at run time.

There are several restrictions on the form of the expression allowed in the operand field of the .IF statement.
SEE ALSO:
.ELSEIF, .ELSE, .ENDIF .REPEAT, .UNTIL, .UNTILCXZ, .WHILE, .ENDW, .BREAK, .CONTINUE
EXAMPLE:
The following code calls a routine, getc, to read a key from the keyboard. It then uses the .IF statement to determine which character to user typed and transfers control to an appropriate routine:
   
INCLUDE Directive
PURPOSE:
Use INCLUDE to incorporate the contents of the file named FileName into your program at the location where the INCLUDE directive occures.
SYNTAX:
INCLUDE FileName
COMMENTS:
The file name FileName can be a full pathname. When you give a full pathname, MASM looks for the file in the specified location only. Otherwise, MASM automatically searches for the file in the directory names specified in the /I option to MASM, the current directory, and the directories listed in the INCLUDE environment variable, in that order. INCLUDE is often used to incorporate a standard set of macro definitions into a program.
EXAMPLE:
    INCLUDE   mymacros.inc ; insert content of file here
    INCLUDE   c:\masm32\include\windows.inc
    INCLUDE   <\masm32\include\kernel32.inc>

INCLUDELIB Directive
PURPOSE:
Use INCLUDELIB to embed information in the object file telling the linker that this module has to be linked with the library named libname. The linker automatically searches for the library file in the current directory, the directoy names specified in the LINK command, and the directories listed in the LIB environment variable, in that order.
SYNTAX:
INCLUDELIB libname
COMMENTS:
The information embedded in the object file by the INCLUDELIB-directive is used by the linker automatically to search the named library file for any external references. The libname argument can only be a file name (if you omit the extension, the default extension is LIB). Full directory pathnames are mot allowed.

If you not use INCLUDELIB and your program needs a library, you can explicitly ask the linker to search a library during linking. The libraryname must be enclosed in angle brackets if it includes a backslash, semicolon, greater-than symbol, less-than symbol, single quotation mark, or double quotation mark.
EXAMPLE:
Suppose your program calls routines from a library named GRAPHICS.LIB. If your program is called TESTPLOT.ASM and if it contains the following statement, you can assemble and link the program TESTPLOT.EXE with the command ml testplot.asm graphics.lib which specifies the name of the library explicitly.
    INCLUDELIB  graphics ; link with GRAPHICS.LIB

INVOKE Directive
PURPOSE:
Use INVOKE to type check and convert paramters and call an assembly language procedure.

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

    * Converts arguments to the expected types.
    * Pushes arguments on the stack in the correct order.
    * Cleans 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, INVOKE can pass a number of arguments different from the number in the parameter list without generating an error or warning. Any additional arguments must be at the end of the INVOKE argument list. All other arguments must match those in the prototype parameter list.
SYNTAX:
INVOKE expression [[, arguments]]

where expression can be the procedure’s label or an indirect reference to a procedure, and arguments can be an expression, a register pair, or an expression preceded with ADDR. (The ADDR operator is discussed later in this chapter.)

Procedures 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, arg2:WORD, arg3:WORD
.
.
.
myproc PROC FAR C PUBLIC 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 assembler can convert some arguments and parameter type combinations so that the correct type can be passed. The signed or unsigned qualities of the arguments in the INVOKE statements determine how the assembler converts them to the types expected by the procedure.

The addup procedure, for example, expects parameters of type WORD, but the arguments passed by INVOKE to the addup procedure can be any of these 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, MASM widens the argument to match.
Widening Arguments
For INVOKE to correctly handle type conversions, you must use the signed data types for any signed assignments. MASM widens an argument to match the type expected by a procedure’s parameters in these cases:

Type Passed Type Expected
BYTE, SBYTE WORD, SWORD, DWORD, SDWORD
WORD, SWORD DWORD, SDWORD

The assembler can extend a segment if far data is expected, and it can convert the type given in the list to the types expected. If the assembler cannot convert the type, however, it generates an error.
Detecting Errors
If the assembler needs to widen an argument, it first copies the value to AL or AX. It widens an unsigned value by placing a zero in the higher register area, and widens a signed value with a CBW, CWD, or CWDE instruction as required. Similarly, the assembler copies a constant argument value into AL or AX when the .8086 directive is in effect. You can see these generated instructions in the listing file when you include the /Sg command-line option.
Using the accumulator register to widen or copy an argument may lead to an error if you attempt to pass AX as another argument. For example, consider the following INVOKE statement for a procedure with the C calling convention

INVOKE myprocA, ax, cx, 100, arg

where arg is a BYTE variable and myproc expects four arguments of type WORD. The assembler widens and then pushes arg like this:

mov al, DGROUP:arg
xor ah, ah
push ax

The generated code thus overwrites the last argument (AX) passed to the procedure. The assembler generates an error in this case, requiring you to rewrite the INVOKE statement.

To summarize, the INVOKE directive overwrites AX and perhaps DX when widening arguments. It also uses AX to push constants on the 8088 and 8086. If you use these registers (or EAX and EDX on an 80386/486) to pass arguments, they may be overwritten. The assembler’s error detection prevents this from ever becoming a run-time bug, but AX and DX should remain your last choice for holding arguments.
Invoking Far Addresses
You can pass a FAR pointer in a segment::offset pair, as shown in the following. Note the use of double colons to separate the register pair. The registers could be any other register 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 SomeProc, ES::BX, arg1, arg2

However, INVOKE cannot combine into a single address one argument for the segment and one for the offset.
Passing an Address
You can use the ADDR operator to pass the address of an expression to a procedure that expects a NEAR or FAR pointer. This example generates code to pass a far pointer (to arg1) to the procedure 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, see TYPEDEF.
Invoking Procedures Indirectly
You can make an indirect procedure call such as call [bx + si] by using a pointer to a function prototype with TYPEDEF, as shown 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 can also use ASSUME to accomplish the same task. The following ASSUME statement associates the type FUNCPTR with the BX register.

ASSUME BX:FUNCPTR
mov bx, OFFSET pfunc
mov si, Num
INVOKE [bx+si], arg1
Checking the Code Generated
Code generated by the INVOKE directive may vary depending on the processor mode and calling conventions in effect. You can check your listing files to see the code generated by the INVOKE directive if you use the /Sg command-line option.
COMMENTS:
The INVOKE macro pushes the specified arguments onto the stack, calls the specified procedure, and cleans up the stack on return (if required). MASM parses the argument list and generates necessary code to push each parameter onto the stack. While parsing the arguments, MASM generates an error if there is a type mismatch and MASM cannot coerce the actual argument to the same type as the formal argument (declared with the PROC or PROTO directive). In order to perform the conversion, MASM may need to use the AX, EAX, DX, and EDX registers. Therefore, you should avoid passing data in these registers if you use the INVOKE macro to call procedures.

When pushing paramters onto the stack, INVOKE uses the parameter parsing mechanism specified in the memory model (the default) or the specific language specified in the PROC or PROTO directive. Likewise, the size of pointers INVOKE pushes on the stack depends (in the default case) on the current memory model.

To take advantage of automatic type conversion, you should use the SBYTE, SWORD, and SDWORD directives when declaring signed paramters and variables. Unless you use these directives, MASM assumes the paramters are unsigned and does not properly sign extend parameters when it converts them from one type to another.
SEE ALSO:
CALL, PROC, PROTO
EXAMPLE:
The following code calls an assembly language procedure which uses the C language calling convention. Note that INVOKE automatically generates the code to push the parameters onto the stack and remove them from the stack after the call (C procedures do not remove the parameters from the stack).

MyProc PROTO FAR C param1:WORD, param2:SWORD, param3:DWORD
       .
       .
       .
       INVOKE MyProc, cx, bl, es:di
       .
       .
       .

In this example, INVOKE pushes CX onto the stack, sign extends BL into AX and pushes AX onto the stack, and it pushes ES and DI onto the stack. After pushing everything, it executes a far call to MyProc. The INVOKE macro also emits code to pop all the paramters oof the stack upon returning from the call (since C functions leave their paramters on the stack).
.MODEL Directive
PURPOSE:
Use .MODEL to select a memory model before using the simplified segmentation directives available in MASM 5.0 and later. The memory can be one of TINY, SMALL, MEDIUM, COMPACT, LARGE, HUGE, or FLAT.
SYNTAX:
.MODEL memory_model [[, langtype]] [[, stackoption]]
COMMENTS:
You use this directive in combination with the simplified segment directives. The .MODEL directive is inserted before any other simplified segment directives appearing in your program. The required memory model operand is mainly to support assembly language procedures that will be called by other high level languages such as C, C++, Delphi, Pascal, BASIC, Fortran, etc. For stand-alone assembly language programs a SMALL model is usually adequate with the below exceptions.

The memory_model operand is a required parameter that determines the size of code and data pointers.

The langtype operand is an optional parameter that sets the calling and naming conventions for procedures and public symbols.

The stackoption operand is not used if memorymodel is FLAT. Also, .MODEL is not used in MASM for x64-bit (ml64.exe). Specifying NEARSTACK groups the stack segment into a single physical segment (DGROUP) along with data. The stack segment register (SS) is assumed to hold the same address as the data segment register (DS). FARSTACK does not group the stack with DGROUP; thus SS does not equal DS.

The following table lists the possible values for each parameter when targeting 16-bit and 32-bit platforms:

Parameter 32-bit values 16-bit values (support for earlier 16-bit development)
memorymodel FLAT TINY, SMALL, COMPACT, MEDIUM, LARGE, HUGE, FLAT
langtype C, STDCALL C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL
stackoption Not used NEARSTACK, FARSTACK
SEE ALSO:
.CODE, .DATA, .STACK, .STARTUP, .EXIT
EXAMPLE:
    .model flat, stdcall   ; Flat, 32-bit memory model (not used in 64-bit)

    .model small, C  

    ; In this sample, the 'X64' define excludes source not used
    ; when targeting the x64 architecture
    ifndef X64
       .686p
       .XMM
       .model flat, C
    endif

AL Register
PURPOSE:
Accumulator, Low Half of AX 8-bit Register (1 Byte Size)
SYNTAX:
AL
COMMENTS:
Accumulator for operands and results data, multiply/divide, string load & store. Used in arithmetic operations.
SEE ALSO:
AX, AH
EXAMPLE:
    mov al, 10   ; move value 10 into AL

AH Register
PURPOSE:
Accumulator, High Half of AX 8-bit Register (1 Byte Size)
SYNTAX:
AH
COMMENTS:
Accumulator for operands and results data, multiply/divide, string load & store. Used in arithmetic operations.
SEE ALSO:
AX, AL
EXAMPLE:
    mov ah, 10   ; move value 10 into AH

AX Register
PURPOSE:
Accumulator 16-bit Register (2 Byte Size)
SYNTAX:
AX
COMMENTS:
Accumulator for operands and results data, multiply/divide, string load & store. Used in arithmetic operations.
SEE ALSO:
AL, AH
EXAMPLE:
    mov ax, 40h   ; move value 40 hex into AX

MOV Mnemonic
PURPOSE:
Move byte or word, original 8086/8088 instruction
SYNTAX:
MOV dest, src
COMMENTS:
Copies byte or word from the source operand to the destination operand. If the destination is SS interrupts are disabled except on early buggy 808x CPUs. Some CPUs disable interrupts if the destination is any of the segment registers.
SEE ALSO:
AX, AH
EXAMPLE:
    mov al, 10   ; move value 10 into AL

FLAT Model
PURPOSE:
The flat memory model is a nonsegmented configuration available in 32-bit operating systems. It is similar to tiny model in that all code and data go in a single 32-bit segment. To write a flat model program, specify the .386, .486, .586, .686 directives before .MODEL FLAT. All data and code (including system resources) are in a single 32-bit segment. The operating system automatically initializes segment registers at load time; you need to modify them only when mixing 16-bit and 32-bit segments in a single application. CS, DS, ES, and SS all occupy the supergroup FLAT. Addresses and pointers passed to system services are always 32-bit near addresses and pointers.
TINY Model
PURPOSE:
Tiny-model programs run only under MS-DOS. Tiny model places all data and code in a single segment. Therefore, the total program file size can occupy no more than 64K. The default is near for code and static data items; you cannot override this default. However, you can allocate far data dynamically at run time using MS-DOS memory allocation services. Tiny model produces MS-DOS .COM files. Specifying .MODEL tiny automatically sends the /TINY argument to the linker. Therefore, the /AT argument is not necessary with .MODEL tiny. However, /AT does not insert a .MODEL directive. It only verifies that there are no base or pointer fixups, and sends /TINY to the linker.