6.3 Using Assembly Language in __asm Blocks

The inline assembler has much in common with other assemblers. For example, it accepts any expression that is legal in MASM. This section describes the use of assembly-language features in __asm blocks.

Instruction Set

The inline assembler supports the full instruction set of the Intel 80286 and 80287 processors. To use 80286 or 80287 instructions, compile with the /G2 option. The inline assembler for CL3232.EXE recognizes 80386- and 80387-specific instructions, so those instructions are available when you write a 32-bit program; the inline assemblers for the other compilers do not recognize those instructions.

Expressions

Inline assembly code can use any MASM expression, which is any combination of operands and operators that evaluates to a single value or address.

Data Directives and Operators

Although an __asm block can reference C or C++ data types and objects, it cannot define data objects with MASM directives or operators. Specifically, you cannot use the definition directives DB, DW, DD, DQ, DT, and DF, or the operators DUP or THIS. MASM structures and records are also unavailable. The inline assembler doesn't accept the directives STRUC, RECORD, WIDTH, or MASK.

EVEN and ALIGN Directives

While the inline assembler doesn't support most MASM directives, it does support EVEN and ALIGN. These directives put NOP (no operation) instructions in the assembly code as needed to align labels to specific boundaries. This makes instruction-fetch operations more efficient for some processors (not including eight-bit processors such as the Intel 8088).

Macros

The inline assembler is not a macro assembler. You cannot use MASM macro directives (MACRO, REPT, IRC, IRP, and ENDM) or macro operators ( <>, !, &, %, and .TYPE). An __asm block can use C preprocessor directives, however. See “Using C and C++ in __asm Blocks,” for more information.

Segment References

You must refer to segments by register rather than by name (the segment name _TEXT is invalid, for instance). Segment overrides must use the register explicitly, as in ES:[BX].

Type and Variable Sizes

The LENGTH, SIZE, and TYPE operators have a limited meaning in inline assembly. They cannot be used at all with the DUP operator (because you cannot define data with MASM directives or operators). But you can use them to find the size of C or C++ variables or types:

The LENGTH operator can return the number of elements in an array. It returns the value 1 for nonarray variables.

The SIZE operator can return the size of a C or C++ variable. A variable's size is the product of its LENGTH and TYPE.

The TYPE operator can return the size of a C or C++ type or variable. If the variable is an array, TYPE returns the size of a single element of the array.

For example, if your program has an eight-element int array,

int arr[8];

the following C and assembly expressions yield the size of arr and its elements:

__asm C Size

LENGTH arr sizeof(arr)/sizeof(arr[0]) 8
SIZE arr sizeof (arr) 16
TYPE arr sizeof(arr[0]) 2

Comments

Instructions in an __asm block can use assembly-language comments:

__asm mov ax, offset buff ; Load address of buff

Because C macros expand into a single logical line, avoid using assembly-language comments in macros (see “Defining __asm Blocks as C Macros”). An __asm block can also contain C-style comments, as noted below.

The _emit Pseudoinstruction

The _emit pseudoinstruction is similar to the DB directive of MASM. It allows you to define a single immediate byte at the current location in the current text segment. However, _emit can define only one byte at a time, and it can only define bytes in the text segment. It uses the same syntax as the INT instruction.

One use for _emit is to define 80386-specific instructions, which the inline assembler does not support. The following fragment, for instance, defines the 80386 CWDE instruction:

/* Assumes 16-bit mode */

#define cwde __asm _emit 0x66 __asm _emit 0x98

.

.

.

__asm {

cwde

}

Debugging and Listings

Programs containing inline assembly code can be debugged with the CodeView debugger, assuming you compile with the /Zi option.

Summary: Inline assembly code can be debugged with CodeView.

Within CodeView, you can set breakpoints on both C or C++ and assembly-language lines. If you enable mixed assembly and source mode, you can display both the source and disassembled form of the assembly code.

Note that putting multiple assembly instructions or source language statements on one line can hamper debugging with CodeView. In source mode, the CodeView debugger lets you set breakpoints on a single line but not on individual statements on the same line. The same principle applies to an __asm block defined as a C macro, which expands to a single logical line.

If you create a mixed source and assembly listing with the /Fc compiler option, the listing contains both the source and assembly forms of each assembly-language line. Macros are not expanded in listings, but they are expanded during compilation.

See the Environment and Tools manual for more information.