A direct memory operand specifies the data at a given address. The address and size of the data are encoded into the internal representation of the instruction. However, the instruction acts on the contents of the address, not the address itself. You must usually specify the size of these operands so that the instruction knows how much memory to operate on.
The offset value of a direct memory operand is not resolved until link time, and the segment must always be in a segment register at run time. The assembler automatically handles address resolution.
You usually represent a direct memory operand in source code as a symbolic name previously declared with a data directive such as BYTE, as illustrated below:
.DATA? ; Segment for uninitialized data
var BYTE ? ; Reserve one byte at current address
; and assign this address to var
.CODE
.
.
.
mov var, al ; Load contents of byte register into
address specified by var
Any location in memory can be a direct memory operand as long as a size is specified and the location is fixed. The data at the address can change, but the address cannot. By default, instructions that use direct memory addressing use the DS register. You can create an expression that points to a memory location using any of the following operators:
Operator Name | Symbol | |
Plus | + | |
Minus | – | |
Index | [ ] | |
Structure member | . | |
Segment override | : |
These operators are discussed in more detail below.
Summary: Several operators can be used in expressions that evaluate to direct memory operands.
The result of combining a memory operand and a constant number with the plus or minus operator is a direct memory operand. However, the result of combining two memory operands with the minus operator is an immediate operand. For example:
memvar EQU array + 5 ; Address five bytes beyond array
immexp EQU mem1 - mem2 ; Distance between addresses
The second expression is legal only if both addresses are in the same segment.
The expression mem1 - mem2 is not relocatable, since the reference to the two labels represents a difference in addresses (offsets). The linker does not need to know about the labels in this statement.
The index operator (brackets enclosing an index value) specifies the register or registers for indirect operands. It should contain a constant index when used with direct memory operands. It is equivalent to the plus operator. For example, the following statements are the same:
mov ax, array[5]
mov ax, array+5
Any direct memory operand can be enclosed in the index operator. The following are equivalent:
mov ax, var
mov ax, [var]
Some programmers prefer to enclose the operand in brackets to show that the contents, not the address, are used.
The structure operator (a period) accesses elements of a structure. A field within a structure variable can be accessed as a direct memory operand:
mov bx, structvar.field1
The address of the structure operand is the sum of the offsets of structvar and field1. See Section 5.2, “Structures and Unions,” for more information about structures.
The segment override operator (a colon) specifies a segment portion of the address that is different from the default segment. When used with instructions, this operator can apply to segment registers or segment names:
mov ax, es:farvar ; Use segment override
The assembler will not generate a segment override if the default segment is explicitly provided. Thus, the following two statements are equivalent:
mov [bx], ax
mov ds:[bx], ax
A segment name override or the segment override operator forces the operand to be an address expression.
mov WORD PTR FARSEG:0, ax ; Segment name override
mov WORD PTR es:100h, ax ; Legal and equivalent
mov WORD PTR es:[100h], ax ; expressions
; mov WORD PTR [100h], ax ; Illegal, not an address
As the example shows, a constant expression cannot be an address expression unless it has a segment override.