问题
The memory addressing general form (found it here) is:
[base + index*scale + disp]
When I try to assemble/compile the following code:
mov eax, [ebx + esp*4 + 2]
NASM gives the following error: "error: invalid effective address".
But the following works fine:
mov eax, [ebx + esp + 2]
And the following works fine also:
mov eax, [ebx + ecx*4 + 2]
So it looks like using a scale
with esp
as the index register causes the error.
Am I correct? and where can I read more about this (other than the Intel manual, which is 4000+ pages long!).
回答1:
The "rules" here are covered well in the Intel IA-32 Architecture manuals. In particular, Volume 1: Basic Architecture contains the following information:
3.7.5 Specifying an Offset
The offset part of a memory address can be specified directly as a static value (called a displacement) or through an address computation made up of one or more of the following components:
- Displacement — An 8-, 16-, or 32-bit value.
- Base — The value in a general-purpose register.
- Index — The value in a general-purpose register.
- Scale factor — A value of 2, 4, or 8 that is multiplied by the index value.
The offset which results from adding these components is called an effective address. Each of these components can have either a positive or negative (2s complement) value, with the exception of the scaling factor. Figure 3-11 shows all the possible ways that these components can be combined to create an effective address in the selected segment.
Figure 3-11. Offset (or Effective Address) ComputationThe uses of general-purpose registers as base or index components are restricted in the following manner:
- The ESP register cannot be used as an index register.
- When the ESP or EBP register is used as the base, the SS segment is the default segment. In all other cases, the DS segment is the default segment.
The base, index, and displacement components can be used in any combination, and any of these components can be NULL. A scale factor may be used only when an index also is used. Each possible combination is useful for data structures commonly used by programmers in high-level languages and assembly language.
The following addressing modes suggest uses for common combinations of address components.
- Displacement ⎯ A displacement alone represents a direct (uncomputed) offset to the operand. Because the displacement is encoded in the instruction, this form of an address is sometimes called an absolute or static address. It is commonly used to access a statically allocated scalar operand.
- Base ⎯ A base alone represents an indirect offset to the operand. Since the value in the base register can change, it can be used for dynamic storage of variables and data structures.
Base + Displacement ⎯ A base register and a displacement can be used together for two distinct purposes:
- As an index into an array when the element size is not 2, 4, or 8 bytes—The displacement component encodes the static offset to the beginning of the array. The base register holds the results of a calculation to determine the offset to a specific element within the array.
- To access a field of a record: the base register holds the address of the beginning of the record, while the displacement is a static offset to the field.
An important special case of this combination is access to parameters in a procedure activation record. A procedure activation record is the stack frame created when a procedure is entered. Here, the EBP register is the best choice for the base register, because it automatically selects the stack segment. This is a compact encoding for this common function.
(Index ∗ Scale) + Displacement ⎯ This address mode offers an efficient way to index into a static array when the element size is 2, 4, or 8 bytes. The displacement locates the beginning of the array, the index register holds the subscript of the desired array element, and the processor automatically converts the subscript into an index by applying the scaling factor.
- Base + Index + Displacement ⎯ Using two registers together supports either a two-dimensional array (the displacement holds the address of the beginning of the array) or one of several instances of an array of records (the displacement is an offset to a field within the record).
- Base + (Index ∗ Scale) + Displacement ⎯ Using all the addressing components together allows efficient indexing of a two-dimensional array when the elements of the array are 2, 4, or 8 bytes in size.
Read and follow these rules, and you will be fine. You don't need to read all 4000 pages, but you really should be familiar enough with the manual's contents that you can look stuff up when needed (like when the assembler coughs up an error message). It's pretty difficult to program a microprocessor without being at all familiar with its design or programming model.
mov eax, [ebx + esp*4 + 2]
is indeed an invalid addressing mode because you are trying to use ESP
as an index. Figure 3-11 says that you can't use ESP
as an index, as does the first bullet point immediately underneath. The logic here is that ESP
is the stack pointer, which contains an address.
It doesn't make sense to scale an address. it does, however, make sense to offset from an address, which is why ESP
can be used as a base. That's why this is fine:
mov eax, [ebx + esp + 2]
This is also fine:
mov eax, [ebx + ecx*4 + 2]
because ECX
can be used as an index.
In the comments, you present this instruction:
mov eax, [ebx + esp + 2]
As Ross Ridge already replied, this is legal because you aren't actually scaling ESP
, so the assembler is smart enough to use ESP
as the base and EBX
as the index. In other words, it has reordered it to:
mov eax, [2 + esp + ebx]
^ ^ ^
| | |
displacement | index
base
with an implicit 1 as the scale factor.
来源:https://stackoverflow.com/questions/44893689/error-addressing-memory-when-usingespscale