3.3. Effective Addresses
========================
An effective address is any operand to an instruction which
references memory. Effective addresses, in NASM, have a very simple
syntax: they consist of an expression evaluating to the desired
address, enclosed in square brackets. For example:
wordvar dw 123
mov ax,[wordvar]
mov ax,[wordvar+1]
mov ax,[es:wordvar+bx]
Anything not conforming to this simple system is not a valid memory
reference in NASM, for example `es:wordvar[bx]'.
More complicated effective addresses, such as those involving more
than one register, work in exactly the same way:
mov eax,[ebx*2+ecx+offset]
mov ax,[bp+di+8]
NASM is capable of doing algebra on these effective addresses, so
that things which don't necessarily _look_ legal are perfectly all
right:
mov eax,[ebx*5] ; assembles as [ebx*4+ebx]
mov eax,[label1*2-label2] ; ie [label1+(label1-label2)]
Some forms of effective address have more than one assembled form;
in most such cases NASM will generate the smallest form it can. For
example, there are distinct assembled forms for the 32-bit effective
addresses `[eax*2+0]' and `[eax+eax]', and NASM will generally generate
the latter on the grounds that the former requires four bytes to store
a zero offset.
NASM has a hinting mechanism which will cause `[eax+ebx]' and
`[ebx+eax]' to generate different opcodes; this is occasionally useful
because `[esi+ebp]' and `[ebp+esi]' have different default segment
registers.
However, you can force NASM to generate an effective address in a
particular form by the use of the keywords `BYTE', `WORD', `DWORD' and
`NOSPLIT'. If you need `[eax+3]' to be assembled using a double-word
offset field instead of the one byte NASM will normally generate, you
can code `[dword eax+3]'. Similarly, you can force NASM to use a byte
offset for a small value which it hasn't seen on the first pass (see
*Note Section 3.8:: for an example of such a code fragment) by using
`[byte eax+offset]'. As special cases, `[byte eax]' will code `[eax+0]'
with a byte offset of zero, and `[dword eax]' will code it with a
double-word offset of zero. The normal form, `[eax]', will be coded
with no offset field.
The form described in the previous paragraph is also useful if you
are trying to access data in a 32-bit segment from within 16 bit code.
For more information on this see the section on mixed-size addressing
(*Note Section 9.2::). In particular, if you need to access data with a
known offset that is larger than will fit in a 16-bit value, if you
don't specify that it is a dword offset, nasm will cause the high word
of the offset to be lost.
Similarly, NASM will split `[eax*2]' into `[eax+eax]' because that
allows the offset field to be absent and space to be saved; in fact, it
will also split `[eax*2+offset]' into `[eax+eax+offset]'. You can
combat this behaviour by the use of the `NOSPLIT' keyword: `[nosplit
eax*2]' will force `[eax*2+0]' to be generated literally.